pax_global_header00006660000000000000000000000064150655663010014521gustar00rootroot0000000000000052 comment=dbf36d9c67a667ec3c1986e2e52f3ebc707185ab TreeLine-3.2.1/000077500000000000000000000000001506556630100132335ustar00rootroot00000000000000TreeLine-3.2.1/.gitignore000066400000000000000000000000511506556630100152170ustar00rootroot00000000000000*.pyc *~ *.swp */__pycache__/ *.hgignore TreeLine-3.2.1/README.md000066400000000000000000000013511506556630100145120ustar00rootroot00000000000000# What is TreeLine? Do you have lots of sticky notes lying around with various useful information jotted down? Or many lists of books, movies, website logins, personal contacts, or things to do? Can you find them when you need them? Well, I often couldn't. So here's my answer. Some would call TreeLine an Outliner, others would call it a PIM. Basically, it just stores almost any kind of information. A tree structure makes it easy to keep things organized. And each node in the tree can contain several fields, forming a mini-database. The output format for each node can be defined, and the output can be shown on the screen, printed, or exported to html. # More Info See the [TreeLine homepage](http://treeline.bellz.org) for more info. TreeLine-3.2.1/doc/000077500000000000000000000000001506556630100140005ustar00rootroot00000000000000TreeLine-3.2.1/doc/INSTALL000066400000000000000000000011401506556630100150250ustar00rootroot00000000000000TreeLine Installation Notes Extract the source files from the treeline tar file, then change to the 'TreeLine' directory in a terminal. For a basic installation, simply execute the following command as root: 'python install.py' If your distribution defaults to Python 2.x, you may need to substitute "python3", "python3.9" or "python3.10" for "python" in these commands. To see all install options, use: 'python install.py -h'. To install TreeLine with a different prefix (the default is '/usr/local'), use: 'python install.py -p /prefix/path'. To skip dependency checks, use: 'python install.py -x'. TreeLine-3.2.1/doc/LICENSE000066400000000000000000000431031506556630100150060ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. TreeLine-3.2.1/doc/basichelp.html000066400000000000000000000122421506556630100166210ustar00rootroot00000000000000 basichelp Views
Tree View - The left-hand view shows a tree of node titles. Parent nodes can be opened and closed to display or hide their indented descendant nodes. Clicking on an already selected node allows the title to be edited. Right-click context menus are available for commonly used functions.

Breadcrumb View - The top pane shows the parent and ancestors of the selected node. It is blank if no nodes or multiple nodes are selected. Ancestors with blue text can be clicked to select those nodes.

Right-hand Views - The right pane is tabbed to show one of three different views of the data. The "Data Output" view shows the formatted text, the "Data Edit" view shows text edit boxes, and the "Title List" view shows an editable list of node titles.

When a parent node is selected in the tree, the right view will default to showing information about the selected node in an upper pane and information about the selected node's children in a lower pane. The "View > Show Child Pane" command will toggle the display of the child nodes. If the selected node has no children, the view will show a single pane with information about the selected node only.

When multiple nodes are selected in the tree (by holding down the shift or Ctrl keys while clicking), the right view will not display any child node information. It will instead show information about every selected node.

When no nodes are selected in the tree (by clicking on a blank area or Ctrl clicking to unselect), the right view will show information about the top-level (root) nodes.

Data Output View - The "Data Output" view shows formatted output text. It cannot be edited from this view.

When the "View > Show Output Descendants" command is toggled, the "Data Output" view will show an indented list with information about every descendant of a single selected node.

Data Edit View - The "Data Edit" view shows a text edit box for each data field within a node. It also shows the node types and the node titles. The types of edit boxes vary based on the field type. Some are just text editors, while others (such as choice fields, date fields, links, etc.) have pull-down menus or dialogs.

Title List View - The "Title List" view shows a list of node titles that can be modified using typical text editor methods. If a new line is typed, a new node is created with that title. If a line is deleted, the corresponding node is removed from the tree.

Editing
Node Menu - The commands in the "Node" menu operate on the selected nodes in the left tree view. There are commands to add or insert nodes, rename node titles and delete nodes. There are also commands to rearrange the tree by changing indent levels or moving nodes up or down. For many of the commands, the descendants of the selected nodes are also affected.

Edit Menu - The edit menu includes undo and redo commands that can fix problems. Cut, copy and paste commands can operate either on text in the right-hand view (if selected or active) or to tree nodes.

Format Menu - The format menu has text formatting commands that are active when using edit boxes in the Data Edit view.

Shortcuts - There are several shortcuts for use in tree editing. Drag and drop will move (or copy if the Ctrl button is held) nodes. Clicking on a selected node will rename it. Pressing the delete key will remove the selected nodes. If desired, these shortcuts can be disabled in "Tools > General Options".

Files
Templates - When starting a new file, a dialog box offers a choice of templates. The default has only a single text field for each node that contains the title. The Long Text template adds a second long text field for more output text. Other templates have various fields for contacts, book lists and to-do lists.

Sample Files - Various TreeLine sample files can be opened by using the "File > Open Sample" command. These have more detail and example content than the new file templates.

Data Types
Node Types - Multiple node data types can be defined in a TreeLine file. Each can contain different data fields and have different output formats. See the template and sample files for examples. Nodes can be set to a specific type using the "Data > Set Node Type" command.

Type Config - The "Data > Configure Data Types" command is used to modify node data types, fields and output formatting. Refer to the Detailed Usage section of the full documentation for details.
TreeLine-3.2.1/doc/basichelp_ru.html000066400000000000000000000372641506556630100173420ustar00rootroot00000000000000 basichelp <!-- Справка по основам --> Формы просмотра (Views)
Панель Дерева (Tree View) - В панели слева показывается дерево заголовков узлов. Родительские узлы могут разворачиваться и сворачиваться для показа или скрытия их дочерних узлов - потомков, отображаемых с отступами. Щелчок по уже выбранному узлу позволяет редактировать его заголовок. Контекстные меню, содержащие часто используемые функции, могут вызываться по щелчку правой кнопкой мыши на узлах.

Панель Навигационной цепочки (Breadcrumb View) - На верхней панели показываются родительский элемент и предки выбранного узла. Панель пуста, если не выбрано ни одного узла или выбрано несколько узлов. По щелчку мыши на узлах предков, выделенных синим цветом, можно выбрать и перейти к этим узлам.

Панели Справа (Right-hand Views) - Панель справа содержит вкладки, показывающие одно из трех различных представлений данных. Во вкладке «Вывод данных» ("Data Output") показывается отформатированный текст, во вкладке «Редактор Данных» ("Data Edit") отображаются поля для редактирования текста, а во вкладке «Список заголовков» редактируемый список заголовков узлов, выбранных в панели дерева.

Когда в дереве выбран родительский узел, на панели справа по умолчанию будет отображаться информация о выбранном узле на верхней части панели и информация о дочерних элементах выбранного узла на нижней части панели. Команда "Вид > Показать Панель Дочернего Узла" ("View > Show Child Pane") будет переключать отображение дочерних узлов. Если выбранный узел не имеет дочерних элементов, во вкладке будет отображаться одна панель с информацией только о выбранном узле.

Когда в дереве выбрано несколько узлов (при удержании нажатой клавиши Shift или нажатии Ctrl), в панели справа не будет отображаться информация о дочерних узлах. Вместо этого будет показана информация о каждом выбранном узле.

Если узлы в дереве не выбраны (при щелчке мышью в пустой области или при нажатии кнопки мыши с одновременным нажатием Ctrl для отмены выбора узла), в панели справа отобразится информация об узле верхнего уровня (корневом).

Панель «Вывод Данных» (Data Output View) - Во вкладке «Вывод Данных» отображается отформатированный для вывода текст. В этой панели текст не может редактироваться.

При переключении команды «Вид > Показать Вывод Потомков» ("View > Show Output Descendants") в панели «Вывод Данных» (Data Output View) отобразится список элементов с отступами, в котором каждый элемент будет содержать информацию о каждом потомке выбранного узла.

Панель «Редактор Данных» (Data Edit View) - Во вкладке «Редактор Данных» (Data Edit) отображаются области редактирования для каждого из полей данных в узле. В ней также показываются типы и заголовки [aka названия] узлов. Типы областей редактирования различаются в зависимости от типов полей. Некоторые из них являются просто полями для редактирования текста, в то время как другие (например, поля выбора, даты, ссылок и т.д.) — выпадающими меню или диалоговыми окнами.

Панель «Список заголовков» (Title List View) - Во вкладке «Список Заголовков» ("Title List") отображается список заголовков [aka названий] узлов, которые можно изменить [в этой панели] как в обычном текстовом редакторе. Если [при редактировании в этой панели] вводится новая строка, то [в результирующем дереве в этом месте] создается новый узел с этим заголовком. Если [при редактировании в этой панели] строка удаляется, соответствующий узел удаляется из дерева.

Редактирование
Меню «Узел» (Node Menu) - Команды в меню «Узел» (Node) выполняются по отношению к выбранным узлам в панели с деревом, располагающейся слева. Имеются команды для создания или вставки узлов, переименования заголовков [aka имен] и удаления узлов. В том числе имеются команды для переупорядочивания структуры дерева, путем смещения узлов между уровнями и перемещения их вверх или вниз. Многие команды также затрагивают потомков выбранных узлов.

Меню «Правка» (Edit Menu) - Меню «Правка» включает команды отмены и повтора, которые могут помочь исправить проблемы. Команды вырезания, копирования и вставки могут выполняться при редактировании текста в панели справа (если она выбрана и активна) или к узлам в дереве.

Меню «Формат» (Format Menu) - В меню «Формат» находятся команды форматирования текста, которые становятся активными при использовании областей редактирования в панели «Редактир Данных».

Быстрый выбор команд (Shortcuts) - В приложении испольуются несколько сочетаний нажатия клавиш клавиатуры и мыши, применяющихся при редактировании дерева. Перетащить и отпустить (drag and drop) переместит (или скопирует, если удерживается кнопка Ctrl) узлы. Щелчок по выбранному узлу переименует его. Нажатие кнопки удаления удалит выбранные узлы. При желании эти команды можно отключить в меню «Инструменты > Общие Параметры» ("Tools > General Options").

Файлы
Шаблоны - Когда создается новый файл, открывается диалоговое окно, предлагающее выбрать один из шаблонов. По умолчанию в каждом узле имеется только одно текстовое поле, содержащее заголовок. В шаблон Длинный Текст (Long Text) добавлено второе поле типа Длинный Текст, предназначенное для вывода текста большого объема. В других шаблонах имеются различные поля для контактов, списков книг и дел.

Файлы Примеров - При помощи команды «Файл > Открыть Пример» ("File > Open Sample") могут быть открыты различные файлы примеров TreeLine. В них содержится более подробная информация, чем в шаблонах новых файлов, и имеются образцы контента.

Типы Данных
Типы узлов - В файлах TreeLine можно определить разнообразные типы данных узла. Каждый тип узла может содержать различные поля данных и иметь различные форматы вывода. Смотрите примеры в файлах шаблонов и примеров. Узлам может быть присвоен конкретный тип при помощи команды «Данные > Назначить тип узла» ("Data > Set Node Type").

Настройка Типов - Команда «Данные > Настроить Типы Данных» ("Data > Configure Data Types") применяется для изменения типов данных узла, полей и форматирования вывода. Обратитесь к разделу Подробности использования в полной документации.
TreeLine-3.2.1/doc/documentation.trln000066400000000000000000006022571506556630100175660ustar00rootroot00000000000000{ "formats": [ { "bullets": true, "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "Text", "lines": 2 } ], "formathtml": true, "formatname": "BULLETS", "icon": "bullet_1", "outputlines": [ "{*Text*}" ], "spacebetween": false, "titleline": "{*Name*}" }, { "childtype": "BULLETS", "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "BULLET_HEADING", "outputlines": [ "{*Name*}" ], "spacebetween": false, "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "HEADINGS", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "Text", "lines": 8 } ], "formathtml": true, "formatname": "HEAD_PARA", "icon": "bullet_2", "outputlines": [ "{*Name*} - {*Text*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "Text", "lines": 8 } ], "formatname": "PARAGRAPH", "icon": "bullet_2", "outputlines": [ "{*Text*}" ], "titleline": "{*Name*}" } ], "nodes": [ { "children": [], "data": { "Name": "Minimize to system tray option", "Text": "A minimize to system tray option was added to General Options (under Features Available). If enabled, it adds a TreeLine system tray icon to toggle application display and hides the taskbar entry when TreeLine is minimized." }, "format": "BULLETS", "uid": "014e1392305b11e9ab99a44cc8e97404" }, { "children": [], "data": { "Name": "Minimize to tray", "Text": "A problem with the option to minimize to the system tray was fixed." }, "format": "BULLETS", "uid": "01d807fc9b0d11f091375847ca7850fa" }, { "children": [], "data": { "Name": "Automatic clone creation", "Text": "Cloned nodes can be created automatically from all identical nodes by using the \"Data > Clone All Matched Nodes\" command." }, "format": "BULLETS", "uid": "04a868f4bb0611e7aea13417ebd53aeb" }, { "children": [], "data": { "Name": "Multiple top-level nodes", "Text": "Multiple top-level (root) nodes are now permitted. When no nodes are selected in the tree (by clicking on a blank area or Ctrl clicking to unselect), the right-hand view will show information about all of the top-level nodes." }, "format": "BULLETS", "uid": "04da8386ba4811e7b3de3417ebd53aeb" }, { "children": [], "data": { "Name": "Updating multiple windows", "Text": "Properly update multiple windows after drag and drop tree changes." }, "format": "BULLETS", "uid": "0906c05bdc8f11ea94fbac675dac20af" }, { "children": [], "data": { "Name": "Reduce windows install size", "Text": "Some unnecessary libraries were eliminated from the Windows installer to reduce download sizes and installed space requirements." }, "format": "BULLETS", "uid": "10c539e2305c11e9a392a44cc8e97404" }, { "children": [], "data": { "Name": "Right view update", "Text": "Properly update the right-hand views after using a new window command." }, "format": "BULLETS", "uid": "145bd91a334c11e896b1d66a6ab671cb" }, { "children": [], "data": { "Name": "Avoid unfocused title edit", "Text": "A click on a tree node to restore tree focus no longer starts editing the node title." }, "format": "BULLETS", "uid": "15da7fde786a11e881c8a44cc8e97404" }, { "children": [], "data": { "Name": "Remove redundant newlines in files", "Text": "Some redundant newline characters were removed from text storage in TreeLine files." }, "format": "BULLETS", "uid": "192373c6305511e9ab21a44cc8e97404" }, { "children": [], "data": { "Name": "Restore data editor cursor & scroll positions", "Text": "Restore the cursor and scroll positions of data editors when the editors are re-created after focus changes." }, "format": "BULLETS", "uid": "194b052fe5d811e9a0d1a44cc8e97404" }, { "children": [ "3e749de3e5d811e98227a44cc8e97404", "194b0537e5d811e989a1a44cc8e97404", "194b0534e5d811e985f6a44cc8e97404" ], "data": { "Name": "October 6, 2019 - Release 3.1.2 (stable release)" }, "format": "HEADINGS", "uid": "194b0533e5d811e9b5fea44cc8e97404" }, { "children": [ "8cdb2406e5df11e9a06da44cc8e97404", "8e8e418ae5dc11e98404a44cc8e97404", "9139627ee5db11e98a21a44cc8e97404", "194b0536e5d811e991b3a44cc8e97404", "fcc1b718e5df11e9a7f9a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "194b0534e5d811e985f6a44cc8e97404" }, { "children": [], "data": { "Name": "Treepad import", "Text": "Fix error due to character encoding when importing files from Treepad." }, "format": "BULLETS", "uid": "194b0536e5d811e991b3a44cc8e97404" }, { "children": [ "194b052fe5d811e9a0d1a44cc8e97404", "ea0c9b24e79911e98abe7054d2175f18", "4212597ee5e011e99b51a44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "194b0537e5d811e989a1a44cc8e97404" }, { "children": [], "data": { "Name": "Enable evaluate HTML tags option", "Text": "The Evaluate HTML tags control was enabled for date, time, boolean and math fields. This allows HTML tags to be evaluated or ignored in more field types." }, "format": "BULLETS", "uid": "1b73aaf4305811e98bb7a44cc8e97404" }, { "children": [], "data": { "Name": "Remove unique ID", "Text": "To improve efficiency, user visible node unique IDs that depend on the node's data have been removed." }, "format": "BULLETS", "uid": "1d015318bb0511e7a2ac3417ebd53aeb" }, { "children": [], "data": { "Name": "Config dialog state", "Text": "Preserve the modified status of the config dialog when switching between windows displaying different files." }, "format": "BULLETS", "uid": "1db7e950fe8011edbb2654b2039ee1f3" }, { "children": [], "data": { "Name": "Reuse TreeLine windows", "Text": "When a file is opened in an existing window, the window is now reused (not just replaced) to eliminate flashing." }, "format": "BULLETS", "uid": "1e3a82e4bb0411e7b7f33417ebd53aeb" }, { "children": [], "data": { "Name": "Child type limits", "Text": "Fix a bug that prevented child type limits from being set back to all types." }, "format": "BULLETS", "uid": "1e7004a8fe8111edbb2654b2039ee1f3" }, { "children": [], "data": { "Name": "Current date/time math field references", "Text": "Added support for current date and time references to math fields. Special field names ({*Now_Date*}, {*Now_Time*} and {*Now_Date_Time*}) must be manually typed in equations." }, "format": "BULLETS", "uid": "221ca8f0305911e99f3fa44cc8e97404" }, { "children": [], "data": { "Name": "German outline nuimbering", "Text": "Add support for German outline numbering using double letters in some levels (thanks to Teresa M)." }, "format": "BULLETS", "uid": "228fa647dc8c11eab28aac675dac20af" }, { "children": [], "data": { "Name": "Empty data edit views", "Text": "Fix a bug in Data Edit views when no fields are visible due to hidden numbering or math fields." }, "format": "BULLETS", "uid": "23b9a763dc8b11ea9dafac675dac20af" }, { "children": [], "data": { "Name": "Save as without filename", "Text": "Fix a minor bug affecting default directories for save-as and export commands when there is not already a file name set." }, "format": "BULLETS", "uid": "25ab9320482011e989f27054d2175f18" }, { "children": [], "data": { "Name": "Math field crash", "Text": "Avoid a crash when bad field name modifiers are in a math field equation." }, "format": "BULLETS", "uid": "273a36a82ca911eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Limit installer deletions", "Text": "In the Windows installer, improve the deletion of files from older versions and avoid problems if installing into a directory shared with other applications." }, "format": "BULLETS", "uid": "2767e530e80411e8aec9a44cc8e97404" }, { "children": [], "data": { "Name": "Math field restrictions", "Text": "Update math field equation restrictions to work with Python 3.8." }, "format": "BULLETS", "uid": "27950877dc8a11ea8902ac675dac20af" }, { "children": [], "data": { "Name": "Fallback character encoding", "Text": "Add fallbacks to UTF-8 encoding if the OS encoding fails on import and export." }, "format": "BULLETS", "uid": "280fe9c42ca911eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Option to keep inaccessible recent files", "Text": "A new general option controls whether inaccessible files are removed from the recent file list at startup. The files are removed by default, but this can be changed to avoid losing listings of files stored on removable drives." }, "format": "BULLETS", "uid": "283565ba334211e8a34bd66a6ab671cb" }, { "children": [], "data": { "Name": "Breadcrumb View", "Text": "The top pane shows the parent and ancestors of the selected node. It is blank if no nodes or multiple nodes are selected. Ancestors with blue text can be clicked to select those nodes." }, "format": "HEAD_PARA", "uid": "28f8844ab58711e79d173417ebd53aeb" }, { "children": [ "f8ed5904813411f0b43b5847ca7850fa" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "293d508c813511f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Conditional type copy/paste & drag/drop", "Text": "Fixed problems with copy / paste and drag / drop on nodes with conditional type settings." }, "format": "BULLETS", "uid": "299ba9e4334a11e881a6d66a6ab671cb" }, { "children": [], "data": { "Name": "Type structure visualization", "Text": "A new Show Configuration Structure command was added to the Data menu. This opens a read-only visualization of complex type structures as another TreeLine file." }, "format": "BULLETS", "uid": "2c9ba0c832ed11e9bf7f7054d2175f18" }, { "children": [], "data": { "Name": "Pretty print output", "Text": "An indent (pretty print) output option was added to General Options (under Features Available). This makes saved TreeLine JSON files easier for humans to read at the expense of somewhat larger file sizes." }, "format": "BULLETS", "uid": "2d4430dc305711e9a33aa44cc8e97404" }, { "children": [], "data": { "Name": "Open with bad references", "Text": "TreeLine files with invalid child references can now be opened. A warning message is given about the missing child nodes in the corrupt file." }, "format": "BULLETS", "uid": "2df5b030bbf711e88a1ca44cc8e97404" }, { "children": [], "data": { "Name": "MacPorts", "Text": "See MacPorts for a third-party port to macOS." }, "format": "PARAGRAPH", "uid": "2fa1be1fdc9511eaa00dac675dac20af" }, { "children": [], "data": { "Name": "Live HTML Export", "Text": "A live tree HTML export creates an interactive view with expandable nodes and a descendant output pane." }, "format": "BULLETS", "uid": "31304c06792b11e888cfa44cc8e97404" }, { "children": [], "data": { "Name": "Restoring window geometry", "Text": "Fix issues with restoring window geometry with multiple monitors and changing configurations." }, "format": "BULLETS", "uid": "35d0914edc8911eab202ac675dac20af" }, { "children": [], "data": { "Name": "Multiple paste commands", "Text": "New paste commands have been added for adding nodes before and after siblings. There are also multiple paste commands for adding clones of nodes." }, "format": "BULLETS", "uid": "39c001f0bb0311e79e793417ebd53aeb" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is a major rewrite of TreeLine. Once it becomes more stable, it will be released as TreeLine version 3.0.0. The 2.1.x unstable series is being discontinued (no stable 2.2.0 release is planned)." }, "format": "BULLETS", "uid": "3d2bb12eba3c11e79b223417ebd53aeb" }, { "children": [], "data": { "Name": "Chinese translation", "Text": "Add a simplified Chinese GUI translation (thanks to Qu Ray for translating)." }, "format": "BULLETS", "uid": "3e749de1e5d811e9a22ba44cc8e97404" }, { "children": [ "3e749de1e5d811e9a22ba44cc8e97404", "cef1d9fee5de11e998dea44cc8e97404" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "3e749de3e5d811e98227a44cc8e97404" }, { "children": [], "data": { "Name": "Time field AM/PM", "Text": "Now forces references to AM/PM in time field formats to be output regardless of system locale settings." }, "format": "BULLETS", "uid": "40ec6d5cbbf711e8bb93a44cc8e97404" }, { "children": [ "8062dece813311f0b43b5847ca7850fa", "293d508c813511f0b43b5847ca7850fa", "8062dd2a813311f0b43b5847ca7850fa" ], "data": { "Name": "August 30, 2025 - Release 3.2.0 (stable release)" }, "format": "HEADINGS", "uid": "414f6662813311f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Outline numbering", "Text": "Change lettered outline numbering sequences to match standards. The sequences change from ...Y, Z, AA, AB, AC... to ...Y, Z, AA, BB, CC..." }, "format": "BULLETS", "uid": "4212597ee5e011e99b51a44cc8e97404" }, { "children": [], "data": { "Name": "Title list select in tree command", "Text": "A Select in Tree command was added to the Title List's right-click context menu. It selects the node corresponding to the current line in the Title List editor. This makes it easier to edit or add children to an item." }, "format": "BULLETS", "uid": "42fb4166305a11e99fd7a44cc8e97404" }, { "children": [], "data": { "Name": "Title edit mouse move", "Text": "Fixed node title editing errors caused by moving the mouse to a data edit box with the title edit still active." }, "format": "BULLETS", "uid": "45491730786a11e8b8e2a44cc8e97404" }, { "children": [], "data": { "Name": "Enter key selects current node", "Text": "The enter key now selects a tree node after the first title letter(s) are typed to make it current (shown with a box around the title)." }, "format": "BULLETS", "uid": "456aa5ca793111e89a30a44cc8e97404" }, { "children": [ "66faed8adc9411ea965eac675dac20af", "d8a76c1fdc9411eaab2dac675dac20af" ], "data": { "Name": "macOS" }, "format": "BULLET_HEADING", "uid": "460699ebdc9411ea89afac675dac20af" }, { "children": [], "data": { "Name": "Dark theme option", "Text": "An optional dark color theme was added to General Options (under Appearances)." }, "format": "BULLETS", "uid": "46f3d0a4305e11e9892fa44cc8e97404" }, { "children": [], "data": { "Name": "Relative paths", "Text": "Avoid issues resolving relative paths between different Windows drive letters in external link fields." }, "format": "BULLETS", "uid": "46fc4054334b11e89299d66a6ab671cb" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is a major rewrite of TreeLine. Once it becomes fully stable, it will be released as TreeLine version 3.0.0." }, "format": "BULLETS", "uid": "4bc47247786711e88b26a44cc8e97404" }, { "children": [ "4bc47249786711e8a3d5a44cc8e97404", "4bc4724c786711e8a8d9a44cc8e97404", "4bc4724f786711e89bdca44cc8e97404" ], "data": { "Name": "June 30, 2018 - Release 2.9.2 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "4bc47248786711e8a8bfa44cc8e97404" }, { "children": [ "4bc4724a786711e8a4dda44cc8e97404", "4bc47247786711e88b26a44cc8e97404", "4bc4724b786711e895e2a44cc8e97404" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "4bc47249786711e8a3d5a44cc8e97404" }, { "children": [], "data": { "Name": "Development snapshot", "Text": "This is a development snapshot of TreeLine that should be considered a release candidate for an upcoming stable release. Many bugs have been fixed. User testing and bug reports are appreciated." }, "format": "BULLETS", "uid": "4bc4724a786711e8a4dda44cc8e97404" }, { "children": [], "data": { "Name": "Translations", "Text": "A GUI translations is available in German. All other translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "4bc4724b786711e895e2a44cc8e97404" }, { "children": [ "57c4de74786911e89c3fa44cc8e97404", "71b708ac786911e88d64a44cc8e97404", "a7d7f61e786911e89bbca44cc8e97404", "15da7fde786a11e881c8a44cc8e97404", "456aa5ca793111e89a30a44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "4bc4724c786711e8a8d9a44cc8e97404" }, { "children": [ "e4fc680a786911e899d3a44cc8e97404", "45491730786a11e8b8e2a44cc8e97404", "f011a5d8786911e8ace3a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "4bc4724f786711e89bdca44cc8e97404" }, { "children": [ "97cd921c2ca811eda95c54b2039ee1f3", "97cd914a2ca811eda95c54b2039ee1f3", "4f1367d62ca811eda95c54b2039ee1f3" ], "data": { "Name": "September 10, 2022 - Release 3.1.5 (stable release)" }, "format": "HEADINGS", "uid": "4f1366fa2ca811eda95c54b2039ee1f3" }, { "children": [ "4f136a742ca811eda95c54b2039ee1f3", "280fe9c42ca911eda95c54b2039ee1f3", "273a36a82ca911eda95c54b2039ee1f3" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "4f1367d62ca811eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Encrypted password", "Text": "Fix a bug preventing a second-try password entry from opening an encrypted file." }, "format": "BULLETS", "uid": "4f136a742ca811eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Print preview", "Text": "Fixed the appearance of the print preview when a dark theme is being used." }, "format": "BULLETS", "uid": "513e664c9b0d11f091375847ca7850fa" }, { "children": [], "data": { "Name": "Multi-session controls", "Text": "Fix problems detecting existing TreeLine sessions when opening files (mostly in Linux)." }, "format": "BULLETS", "uid": "5337587ddc8811eaaaedac675dac20af" }, { "children": [], "data": { "Name": "Clone removal", "Text": "The new \"Data > Detach Clones\" command converts cloned nodes in selected branches back into independent nodes." }, "format": "BULLETS", "uid": "5647bc8cbb0611e783853417ebd53aeb" }, { "children": [], "data": { "Name": "German translation", "Text": "The German GUI translation was updated (thanks to Maria Seliger)." }, "format": "BULLETS", "uid": "57c4de74786911e89c3fa44cc8e97404" }, { "children": [ "57d4af20fe7f11edbb2654b2039ee1f3", "57d4acd2fe7f11edbb2654b2039ee1f3" ], "data": { "Name": "June 3, 2023 - Release 3.1.6 (stable release)" }, "format": "HEADINGS", "uid": "57d4ac00fe7f11edbb2654b2039ee1f3" }, { "children": [ "1e7004a8fe8111edbb2654b2039ee1f3", "1db7e950fe8011edbb2654b2039ee1f3", "57d4ad9afe7f11edbb2654b2039ee1f3", "df7baad6fe8011edbb2654b2039ee1f3", "67cea5cefe8011edbb2654b2039ee1f3" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "57d4acd2fe7f11edbb2654b2039ee1f3" }, { "children": [], "data": { "Name": "Close dialogs with escape key", "Text": "Fix problems occurring when the escape key is used to close various non-modal dialogs." }, "format": "BULLETS", "uid": "57d4ad9afe7f11edbb2654b2039ee1f3" }, { "children": [], "data": { "Name": "External file modification", "Text": "Detect external file modifications by checking the file's last modified time just prior to saving." }, "format": "BULLETS", "uid": "57d4ae62fe7f11edbb2654b2039ee1f3" }, { "children": [ "57d4ae62fe7f11edbb2654b2039ee1f3", "a4ab733cfe8011edbb2654b2039ee1f3" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "57d4af20fe7f11edbb2654b2039ee1f3" }, { "children": [], "data": { "Name": "Linux menus", "Text": "Added a desktop specification file to the Linux installer for desktop environment menu support." }, "format": "BULLETS", "uid": "58dddee4010f11e88925d66a6ab671cb" }, { "children": [], "data": { "Name": "Setting types", "Text": "Each tree node can be set to a type format independently." }, "format": "BULLETS", "uid": "5c1d58ac792a11e8b78ca44cc8e97404" }, { "children": [], "data": { "Name": "Category level swap", "Text": "A new \"Swap Category Levels\" command swaps child and grandchild nodes beneath a selected node. A child node with multiple nodes under it will become cloned under each one. Any existing grandchild clones will become individual nodes with multiple children." }, "format": "BULLETS", "uid": "5c90e0b0bb0611e78e443417ebd53aeb" }, { "children": [], "data": { "Name": "Cloned nodes", "Text": "Cloned nodes (the same nodes with multiple parents/locations) can be created using special paste commands or by automatically matching identical nodes." }, "format": "BULLETS", "uid": "5f12f768b32c11e7a41a3417ebd53aeb" }, { "children": [], "data": { "Name": "Library updates", "Text": "Update the libraries used to build the Windows binaries to Python 3.8 and Qt/PyQt 5.14." }, "format": "BULLETS", "uid": "603e11fadf2011eaa12e7054d2175f18" }, { "children": [ "2fa1be1fdc9511eaa00dac675dac20af" ], "data": { "Name": "macOS" }, "format": "BULLET_HEADING", "uid": "611e03ffdc9411ea930eac675dac20af" }, { "children": [ "6515826e9b0c11f091375847ca7850fa" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "65157efe9b0c11f091375847ca7850fa" }, { "children": [ "65157efe9b0c11f091375847ca7850fa", "651580529b0c11f091375847ca7850fa" ], "data": { "Name": "September 27, 2025 - Release 3.2.1 (stable release)" }, "format": "HEADINGS", "uid": "65157f8a9b0c11f091375847ca7850fa" }, { "children": [ "78f991de9b0d11f091375847ca7850fa", "651580ac9b0c11f091375847ca7850fa", "513e664c9b0d11f091375847ca7850fa", "a5a948289b0d11f091375847ca7850fa", "01d807fc9b0d11f091375847ca7850fa" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "651580529b0c11f091375847ca7850fa" }, { "children": [], "data": { "Name": "Print page sizes", "Text": "An error setting some page sizes for printing was fixed." }, "format": "BULLETS", "uid": "651580ac9b0c11f091375847ca7850fa" }, { "children": [], "data": { "Name": "Color themes", "Text": "Added an easily selectable light-colored theme option." }, "format": "BULLETS", "uid": "6515826e9b0c11f091375847ca7850fa" }, { "children": [], "data": { "Name": "TreeLine Export", "Text": "Files can be exported that are compatible with older versions of TreeLine (1.x and 2.x), with a \".trl\" file extension. Some newer features, such as cloned nodes and multiple root nodes may not be completely preserved. TreeLine subtrees can also be exported to save just selected branches of the tree to a file using the current TreeLine version." }, "format": "HEAD_PARA", "uid": "65289b36b97611e783eb3417ebd53aeb" }, { "children": [], "data": { "Name": "Custom time dialog", "Text": "Added a custom time select dialog box for editing Time and TimeDate fields." }, "format": "BULLETS", "uid": "653f2f90334c11e8a7c9d66a6ab671cb" }, { "children": [], "data": { "Name": "Printing long nodes", "Text": "Multiple issues with printing long nodes were fixed." }, "format": "BULLETS", "uid": "6610203dd2c111e8a95ad66a6ab671cb" }, { "children": [ "66102040d2c111e8a210d66a6ab671cb", "66102041d2c111e8bd85d66a6ab671cb" ], "data": { "Name": "October 20, 2018 - Release 3.0.2 (stable release)" }, "format": "HEADINGS", "uid": "6610203fd2c111e8b033d66a6ab671cb" }, { "children": [ "66102049d2c111e8bb55d66a6ab671cb" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "66102040d2c111e8a210d66a6ab671cb" }, { "children": [ "66102043d2c111e88d57d66a6ab671cb", "6610203dd2c111e8a95ad66a6ab671cb", "66102048d2c111e89f4cd66a6ab671cb" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "66102041d2c111e8bd85d66a6ab671cb" }, { "children": [], "data": { "Name": "Windows printing", "Text": "Fixed nonfunctional printing commands under Windows by building the Windows binary using PyInstaller rather than cx_Freeze." }, "format": "BULLETS", "uid": "66102043d2c111e88d57d66a6ab671cb" }, { "children": [], "data": { "Name": "Blanks as zeros", "Text": "Fixed problems saving files when the blanks as zeros property was changed for math fields." }, "format": "BULLETS", "uid": "66102048d2c111e89f4cd66a6ab671cb" }, { "children": [], "data": { "Name": "Python 3.7", "Text": "Upgraded the Windows binary from Python 3.6 to Python 3.7." }, "format": "BULLETS", "uid": "66102049d2c111e8bb55d66a6ab671cb" }, { "children": [], "data": { "Name": "Not supported", "Text": "Due to a lack of Macs for testing, TreeLine on macOS is not formally supported." }, "format": "BULLETS", "uid": "66faed8adc9411ea965eac675dac20af" }, { "children": [], "data": { "Name": "Live HTML export", "Text": "Fix a bug using child count fields in live HTML exports." }, "format": "BULLETS", "uid": "67cea5cefe8011edbb2654b2039ee1f3" }, { "children": [ "67e95a5fbbf611e8b8bda44cc8e97404", "67e95a60bbf611e8a80ca44cc8e97404" ], "data": { "Name": "September 29, 2018 - Release 3.0.1 (stable release)" }, "format": "HEADINGS", "uid": "67e95a5bbbf611e891f7a44cc8e97404" }, { "children": [ "f966db0cc23f11e8b80fd66a6ab671cb", "67e95a61bbf611e8989ca44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "67e95a5fbbf611e8b8bda44cc8e97404" }, { "children": [ "67e95a64bbf611e8960fa44cc8e97404", "2df5b030bbf711e88a1ca44cc8e97404", "dc700fb4c24211e8b88dd66a6ab671cb", "40ec6d5cbbf711e8bb93a44cc8e97404", "9550a81ac24111e89029d66a6ab671cb", "71e2f25cc24211e88524d66a6ab671cb", "a757f64ac24211e8a95fd66a6ab671cb", "bdc8628ec2bd11e889e57054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "67e95a60bbf611e8a80ca44cc8e97404" }, { "children": [], "data": { "Name": "About dialog text box", "Text": "Added a read-only text box to the Help > About dialog to allow copying of the version and library information." }, "format": "BULLETS", "uid": "67e95a61bbf611e8989ca44cc8e97404" }, { "children": [], "data": { "Name": "Old file import", "Text": "Fixed a problem opening old TreeLine files that had format changes in File Info fields." }, "format": "BULLETS", "uid": "67e95a64bbf611e8960fa44cc8e97404" }, { "children": [], "data": { "Name": "Data in config structure", "Text": "Added many Show Configuration Structure data fields to show detailed settings for type formats and field formats.." }, "format": "BULLETS", "uid": "6a6067d4482011e989f27054d2175f18" }, { "children": [], "data": { "Name": "Select top node at open", "Text": "The top root node is now selected at file open if there is not a recent selection state to restore. Previously these files opened with no selection, which could cause confusion." }, "format": "BULLETS", "uid": "6a98186e305c11e99fbfa44cc8e97404" }, { "children": [], "data": { "Name": "Insert date command", "Text": "Add an Insert Date command that adds a timestamp to text field edit boxes." }, "format": "BULLETS", "uid": "6c916f15dc8c11ea9dbeac675dac20af" }, { "children": [], "data": { "Name": "Child type limits", "Text": "Child node types that are available to be set can be limited. A new pull-down list of child type limits is in the \"Type Config\" tab of the configuration dialog if the advanced functions are shown." }, "format": "BULLETS", "uid": "6dc88226bb0711e7894d3417ebd53aeb" }, { "children": [ "6df9a0c6ba3b11e7925d3417ebd53aeb", "6df9a0c9ba3b11e7a9793417ebd53aeb" ], "data": { "Name": "January 28, 2018 - Release 2.9.0 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "6df9a0c5ba3b11e78e7e3417ebd53aeb" }, { "children": [ "6df9a0c7ba3b11e7b7bd3417ebd53aeb", "3d2bb12eba3c11e79b223417ebd53aeb", "6df9a0c8ba3b11e78d783417ebd53aeb" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "6df9a0c6ba3b11e7925d3417ebd53aeb" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It could contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) is recommended for critical work." }, "format": "BULLETS", "uid": "6df9a0c7ba3b11e7b7bd3417ebd53aeb" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "6df9a0c8ba3b11e78d783417ebd53aeb" }, { "children": [ "6df9a0caba3b11e78b283417ebd53aeb", "d1d8e56eba4011e784ab3417ebd53aeb", "04da8386ba4811e7b3de3417ebd53aeb", "e6ad9f6eba4311e796bd3417ebd53aeb", "cd28e024bb0211e79c553417ebd53aeb", "1e3a82e4bb0411e7b7f33417ebd53aeb", "98132868ba4511e7b7283417ebd53aeb", "39c001f0bb0311e79e793417ebd53aeb", "04a868f4bb0611e7aea13417ebd53aeb", "5647bc8cbb0611e783853417ebd53aeb", "5c90e0b0bb0611e78e443417ebd53aeb", "6dc88226bb0711e7894d3417ebd53aeb", "7697b826bb0411e788433417ebd53aeb", "1d015318bb0511e7a2ac3417ebd53aeb", "f5983b38bb0411e795e13417ebd53aeb", "58dddee4010f11e88925d66a6ab671cb" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "6df9a0c9ba3b11e7a9793417ebd53aeb" }, { "children": [], "data": { "Name": "New file format", "Text": "TreeLine files now uses a new JSON format in place of the old XML format. This provides more flexibility for structuring new features like cloned nodes and multiple root nodes. A new file extension (\".trln) helps to distinguish these files." }, "format": "BULLETS", "uid": "6df9a0caba3b11e78b283417ebd53aeb" }, { "children": [], "data": { "Name": "Maintain expanded nodes", "Text": "The expand/collapse status of nearby nodes is maintained while editing the node structure. This includes adding, deleting, moving and indenting nodes." }, "format": "BULLETS", "uid": "71b708ac786911e88d64a44cc8e97404" }, { "children": [], "data": { "Name": "Complex data menu commands", "Text": "Fixed various errors when applying advanced clone and category commands from the Data menu to complex node structures." }, "format": "BULLETS", "uid": "71e2f25cc24211e88524d66a6ab671cb" }, { "children": [], "data": { "Name": "Date and time formats", "Text": "The Date, Time and DateTime fields have new format strings that enable extra text to be added to the date output." }, "format": "BULLETS", "uid": "7697b826bb0411e788433417ebd53aeb" }, { "children": [], "data": { "Name": "Number field formatting", "Text": "Fixed problems with number field formatting when using a \",\" radix with exponents." }, "format": "BULLETS", "uid": "7716c96e334a11e896bfd66a6ab671cb" }, { "children": [], "data": { "Name": "Drag and drop", "Text": "Fixed errors that occurred when dragging and dropping nodes and files." }, "format": "BULLETS", "uid": "78f991de9b0d11f091375847ca7850fa" }, { "children": [], "data": { "Name": "Math field expressions", "Text": "Evaluate math expressions contained in fields that are referenced by math field equations. " }, "format": "BULLETS", "uid": "7a9ace43dc8a11ea9e9bac675dac20af" }, { "children": [], "data": { "Name": "Translations", "Text": "Translations of the TreeLine GUI are available in German and Spanish. The translation should load automatically if the OS locale is properly set. Alternatively, \"--lang xx\" can be appended to the command that starts TreeLine, where \"xx\" is the two-letter language code (\"en\", \"de\" or \"es\")." }, "format": "HEAD_PARA", "uid": "7e9b3b88c24511e896c7d66a6ab671cb" }, { "children": [], "data": { "Name": "Word count equation", "Text": "Added a word count function for math field types." }, "format": "BULLETS", "uid": "7f0da0fc813511f0b43b5847ca7850fa" }, { "children": [ "7ffeb672dc8711ea86ddac675dac20af", "7ffeb670dc8711ea81aeac675dac20af", "7ffeb66edc8711eaaa13ac675dac20af" ], "data": { "Name": "August 16, 2020 - Release 3.1.3 (stable release)" }, "format": "HEADINGS", "uid": "7ffeb66ddc8711ea9a87ac675dac20af" }, { "children": [ "d9119485dc8711ea92dcac675dac20af", "8d9c1717dc8811ea9c40ac675dac20af", "cf9c139fdc8e11ea8261ac675dac20af", "88bb6300dc8e11ea9a73ac675dac20af", "b6a4a6bddc8911ea8612ac675dac20af", "23b9a763dc8b11ea9dafac675dac20af", "0906c05bdc8f11ea94fbac675dac20af", "35d0914edc8911eab202ac675dac20af", "f2a0c0a1dc8d11ea8921ac675dac20af", "5337587ddc8811eaaaedac675dac20af" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "7ffeb66edc8711eaaa13ac675dac20af" }, { "children": [ "27950877dc8a11ea8902ac675dac20af", "c1f8dca5dc9511ea8f76ac675dac20af", "603e11fadf2011eaa12e7054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "7ffeb670dc8711ea81aeac675dac20af" }, { "children": [ "dca5b84fdc8a11eab098ac675dac20af", "6c916f15dc8c11ea9dbeac675dac20af", "7a9ace43dc8a11ea9e9bac675dac20af", "228fa647dc8c11eab28aac675dac20af" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "7ffeb672dc8711ea86ddac675dac20af" }, { "children": [ "800a0972305111e9a7fea44cc8e97404", "f7bbd909305111e9be43a44cc8e97404", "800a0975305111e9a018a44cc8e97404", "800a0976305111e9bd43a44cc8e97404" ], "data": { "Name": "February 20, 2019 - Release 3.1.0 (beta release)" }, "format": "HEADINGS", "uid": "800a0971305111e991cda44cc8e97404" }, { "children": [ "800a0973305111e9b7b9a44cc8e97404", "800a0974305111e99f0fa44cc8e97404" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "800a0972305111e9a7fea44cc8e97404" }, { "children": [], "data": { "Name": "Beta release", "Text": "This is a beta release of TreeLine. Some new features have not been extensively tested, but major bugs are unlikely. Testing and bug reports are appreciated, but those with very critical work should consider using the stable release (TreeLine 3.0.x)." }, "format": "BULLETS", "uid": "800a0973305111e9b7b9a44cc8e97404" }, { "children": [], "data": { "Name": "Translations", "Text": "GUI translations are available in German and Spanish, but they still require minor updates to cover recent changes. Volunteers are also needed to update or create translations in additional languages." }, "format": "BULLETS", "uid": "800a0974305111e99f0fa44cc8e97404" }, { "children": [ "6a98186e305c11e99fbfa44cc8e97404", "800a0977305111e98c38a44cc8e97404", "10c539e2305c11e9a392a44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "800a0975305111e9a018a44cc8e97404" }, { "children": [ "800a097a305111e9950ba44cc8e97404", "192373c6305511e9ab21a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "800a0976305111e9bd43a44cc8e97404" }, { "children": [], "data": { "Name": "Gray out data edit view math fields", "Text": "Non-editable math fields in the Data Edit view show as gray when the mouse hovers over them." }, "format": "BULLETS", "uid": "800a0977305111e98c38a44cc8e97404" }, { "children": [], "data": { "Name": "Titles from HTML text fields", "Text": "Fixed the truncation of node titles that are generated from the first line of HTML Text fields." }, "format": "BULLETS", "uid": "800a097a305111e9950ba44cc8e97404" }, { "children": [ "8062dd8e813311f0b43b5847ca7850fa", "c31396d6813411f0b43b5847ca7850fa", "9fdb2b84813411f0b43b5847ca7850fa" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "8062dd2a813311f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Closing windows", "Text": "Fixed errors closing a window if the same file is open in another window." }, "format": "BULLETS", "uid": "8062dd8e813311f0b43b5847ca7850fa" }, { "children": [ "8062df28813311f0b43b5847ca7850fa", "7f0da0fc813511f0b43b5847ca7850fa" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "8062dece813311f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Port to Qt6", "Text": "Made extensive updates to port TreeLine to the Qt6 and PyQt6 libraries." }, "format": "BULLETS", "uid": "8062df28813311f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Numbering", "Text": "Fix incorrect numbering updates in some situations with mixed node types." }, "format": "BULLETS", "uid": "84b24010482211e989f27054d2175f18" }, { "children": [], "data": { "Name": "Circular math errors", "Text": "Fix problems opening files that contain circular reference errors in math fields." }, "format": "BULLETS", "uid": "88bb6300dc8e11ea9a73ac675dac20af" }, { "children": [], "data": { "Name": "Truncated text export", "Text": "Fix a bug that truncated plain text exports after the first line." }, "format": "BULLETS", "uid": "8cdb2406e5df11e9a06da44cc8e97404" }, { "children": [], "data": { "Name": "Find & replace error", "Text": "Avoid an application error when a Find and Replace command causes fields to contain invalid data." }, "format": "BULLETS", "uid": "8d9c1717dc8811ea9c40ac675dac20af" }, { "children": [], "data": { "Name": "Title list select in tree", "Text": "Enable the title list view's select in tree context menu to be used on new child nodes." }, "format": "BULLETS", "uid": "8e8e418ae5dc11e98404a44cc8e97404" }, { "children": [], "data": { "Name": "Copy command errors", "Text": "Fix errors shown when using copy commands after closing TreeLine windows." }, "format": "BULLETS", "uid": "90dbc4e4334b11e892d0d66a6ab671cb" }, { "children": [], "data": { "Name": "Dark mode tooltips", "Text": "Modify dark mode colors to make tool tips visible." }, "format": "BULLETS", "uid": "9139627ee5db11e98a21a44cc8e97404" }, { "children": [], "data": { "Name": "Purge old field data", "Text": "Data from fields that were removed from the configuration is now purged when a file is saved. This avoids missing matches in the Clone All Matched Nodes command." }, "format": "BULLETS", "uid": "9550a81ac24111e89029d66a6ab671cb" }, { "children": [], "data": { "Name": "Old TreeLine Import", "Text": "Files from older versions of TreeLine (1.x or 2.x) can be imported. These files are in XML format and generally have a \".trl\" file extension (current files are in JSON format with a \".trln\" file extension). Unlike other file imports, these older files will import without showing the import dialog box when using the \"File > Open\" command." }, "format": "HEAD_PARA", "uid": "95547c38b97411e7a42a3417ebd53aeb" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is a major rewrite of TreeLine. Once it becomes more stable, it will be released as TreeLine version 3.0.0. The 2.1.x unstable series is being discontinued (no stable 2.2.0 release is planned)." }, "format": "BULLETS", "uid": "95a6e905333f11e886edd66a6ab671cb" }, { "children": [ "95a6e90b333f11e8976fd66a6ab671cb", "95a6e90e333f11e88696d66a6ab671cb", "b16866da333f11e88adbd66a6ab671cb" ], "data": { "Name": "March 31, 2018 - Release 2.9.1 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "95a6e90a333f11e89efed66a6ab671cb" }, { "children": [ "95a6e90c333f11e8b766d66a6ab671cb", "95a6e905333f11e886edd66a6ab671cb", "95a6e90d333f11e8b88ed66a6ab671cb" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "95a6e90b333f11e8976fd66a6ab671cb" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It has improved but could still contain bugs. Testing and bug reports are appreciated, but those with very critical work should consider using the stable release (TreeLine 2.0.x)." }, "format": "BULLETS", "uid": "95a6e90c333f11e8b766d66a6ab671cb" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "95a6e90d333f11e8b88ed66a6ab671cb" }, { "children": [ "b1cd1f82334111e8b89ad66a6ab671cb", "dd22e382334111e894e6d66a6ab671cb", "653f2f90334c11e8a7c9d66a6ab671cb", "283565ba334211e8a34bd66a6ab671cb" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "95a6e90e333f11e88696d66a6ab671cb" }, { "children": [], "data": { "Name": "Child count equation references", "Text": "Eliminate a problem defining math field equations that include child count references." }, "format": "BULLETS", "uid": "95d970aa481f11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Printed line width", "Text": "For better visibility, increase the width of tree structure lines in printed and PDF output files." }, "format": "BULLETS", "uid": "97cd8dda2ca811eda95c54b2039ee1f3" }, { "children": [ "97cd8dda2ca811eda95c54b2039ee1f3", "c5c45e3e2d4411eda95c54b2039ee1f3", "c771aa162ca911eda95c54b2039ee1f3", "c8eb2e4e2ca911eda95c54b2039ee1f3" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "97cd914a2ca811eda95c54b2039ee1f3" }, { "children": [ "97cd93ac2ca811eda95c54b2039ee1f3" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "97cd921c2ca811eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Strike-through font", "Text": "Add a command for strike-through font formatting." }, "format": "BULLETS", "uid": "97cd93ac2ca811eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Native cloned nodes", "Text": "Cloned nodes now have a more native and efficient implementation. This allows the same nodes to have multiple parents. The new breadcrumb view shows a list of clones for the selected node that can be clicked to select the other instances." }, "format": "BULLETS", "uid": "98132868ba4511e7b7283417ebd53aeb" }, { "children": [], "data": { "Name": "Format Menu", "Text": "The format menu has text formatting commands that are active when using edit boxes in the Data Edit view." }, "format": "HEAD_PARA", "uid": "997af664b58811e7ac243417ebd53aeb" }, { "children": [], "data": { "Name": "Ancestor field references", "Text": "Fixed problems with advanced ancestor field output references in some tree locations." }, "format": "BULLETS", "uid": "9a8a1400334c11e89838d66a6ab671cb" }, { "children": [], "data": { "Name": "Old TreeLine import/export", "Text": "Files from older versions of TreeLine (2.x and 1.x) can be imported and exported." }, "format": "BULLETS", "uid": "9bd80f34b32b11e7be613417ebd53aeb" }, { "children": [], "data": { "Name": "Portable config", "Text": "Problems with writing config files in Windows portable installations were fixed." }, "format": "BULLETS", "uid": "9c08f39de80311e8b791a44cc8e97404" }, { "children": [ "9c08f3a0e80311e8b2e0a44cc8e97404" ], "data": { "Name": "November 17, 2018 - Release 3.0.3 (stable release)" }, "format": "HEADINGS", "uid": "9c08f39ee80311e8a510a44cc8e97404" }, { "children": [ "9c08f3a1e80311e884dca44cc8e97404", "9c08f39de80311e8b791a44cc8e97404", "9c08f3a2e80311e88128a44cc8e97404", "2767e530e80411e8aec9a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "9c08f3a0e80311e8b2e0a44cc8e97404" }, { "children": [], "data": { "Name": "Child count fields", "Text": "Fixed an error when adding child count fields to the output format." }, "format": "BULLETS", "uid": "9c08f3a1e80311e884dca44cc8e97404" }, { "children": [], "data": { "Name": "Config file error handling", "Text": "Improved error handling after failing to read or write config files." }, "format": "BULLETS", "uid": "9c08f3a2e80311e88128a44cc8e97404" }, { "children": [], "data": { "Name": "Generic XML input", "Text": "Improved the handling of multi-line text in generic XML import." }, "format": "BULLETS", "uid": "9fdb2b84813411f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Colors", "Text": "The default GUI colors can be changed using the \"Tools > Customize Colors\" dialog. A dark theme is available, or individual colors can be selected." }, "format": "HEAD_PARA", "uid": "9ff09734dc9011ea887bac675dac20af" }, { "children": [], "data": { "Name": "Convert between Choice and Combination", "Text": "Preserve the choices in the field format when switching between Choice and Combination field types." }, "format": "BULLETS", "uid": "a4ab733cfe8011edbb2654b2039ee1f3" }, { "children": [], "data": { "Name": "Time editor", "Text": "Fixed the appearance of the time edit widget when used with a dark theme." }, "format": "BULLETS", "uid": "a5a948289b0d11f091375847ca7850fa" }, { "children": [], "data": { "Name": "Complex undo operations", "Text": "Fixed some problems with using the Undo command after complex operations." }, "format": "BULLETS", "uid": "a757f64ac24211e8a95fd66a6ab671cb" }, { "children": [], "data": { "Name": "Save state for discarded files", "Text": "The expanded/collapsed and selected tree states are now saved even if changes were discarded in the previous session." }, "format": "BULLETS", "uid": "a7d7f61e786911e89bbca44cc8e97404" }, { "children": [], "data": { "Name": "Pull-downs on repeated dialog boxes", "Text": "Fixed issues on Windows with pull-down combo boxes not working after repeatedly showing some dialogs (mostly find and filter dialogs)." }, "format": "BULLETS", "uid": "a7fa190c334911e88d18d66a6ab671cb" }, { "children": [], "data": { "Name": "Child Type Limits", "Text": "In addition to setting the default child type, the child node types that are available to be set can be limited. There is a pull-down list of child type limits in the \"Type Config\" tab of the configuration dialog if the advanced functions are shown. Only checked types will show up in the type lists when using the \"Data > Set Node Type\" command on a child node." }, "format": "HEAD_PARA", "uid": "aa6f6ca4bb0711e7bbf43417ebd53aeb" }, { "children": [ "90dbc4e4334b11e892d0d66a6ab671cb", "299ba9e4334a11e881a6d66a6ab671cb", "e46163b4334b11e88512d66a6ab671cb", "a7fa190c334911e88d18d66a6ab671cb", "f817e5b6334a11e89349d66a6ab671cb", "7716c96e334a11e896bfd66a6ab671cb", "46fc4054334b11e89299d66a6ab671cb", "9a8a1400334c11e89838d66a6ab671cb", "145bd91a334c11e896b1d66a6ab671cb", "edd50b80334c11e8b5f5d66a6ab671cb", "b7ec7052334a11e88325d66a6ab671cb" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "b16866da333f11e88adbd66a6ab671cb" }, { "children": [], "data": { "Name": "Breadcrumb view", "Text": "An upper breadcrumb view shows titles of the selected node's ancestors; the titles can be clicked to select them in the tree." }, "format": "BULLETS", "uid": "b1b5d434b32911e780fd3417ebd53aeb" }, { "children": [], "data": { "Name": "Live tree HTML export", "Text": "A new HTML export uses Javascript and CSS to create a live tree view. Nodes in the tree can be expanded and collapsed, and a separate pane shows the output for all descendants of the selected node. One form of this export creates separate files that are linked to the existing TreeLine file. These files are intended for use on a web server (browser security usually prevents local access). Only the TreeLine file needs to be replaced to update the data (re-export is not required). The second form creates a single file (with embedded data) that can be accessed from a local web browser." }, "format": "BULLETS", "uid": "b1cd1f82334111e8b89ad66a6ab671cb" }, { "children": [], "data": { "Name": "Search and replace", "Text": "Added support for finding and replacing empty data fields using the search and replace command." }, "format": "BULLETS", "uid": "b398d8ee482211e989f27054d2175f18" }, { "children": [ "b5fe6aa030e111ebbc097054d2175f18" ], "data": { "Name": "November 27, 2020 - Release 3.1.4 (stable release)" }, "format": "HEADINGS", "uid": "b5fe698830e111ebbc097054d2175f18" }, { "children": [ "b5fe74c830e111ebbc097054d2175f18", "b5fe6f0030e111ebbc097054d2175f18", "b5fe737e30e111ebbc097054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "b5fe6aa030e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Window closing error", "Text": "Avoid an error message when a window is closed with the focus on a dialog box." }, "format": "BULLETS", "uid": "b5fe6f0030e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Math field root reference", "Text": "Fix a problem recalculating root references in field equations." }, "format": "BULLETS", "uid": "b5fe737e30e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Python 3.9 compatible", "Text": "Fix an incompatibility with the new Python 3.9 version under Linux or running from source." }, "format": "BULLETS", "uid": "b5fe74c830e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Font dialog bug", "Text": "Avoid problems with empty parameters in the font dialogs." }, "format": "BULLETS", "uid": "b6a4a6bddc8911ea8612ac675dac20af" }, { "children": [], "data": { "Name": "Output table spacing", "Text": "Fixed minor spacing issues for tables shown in output views and HTML exports." }, "format": "BULLETS", "uid": "b7ec7052334a11e88325d66a6ab671cb" }, { "children": [], "data": { "Name": "Math Fields", "Text": "For more complex output formatting, the math field can be used to combine other fields using various mathematical, relational and string operators. See the Math Type section for details." }, "format": "HEAD_PARA", "uid": "bbbf735ac24711e8b560d66a6ab671cb" }, { "children": [], "data": { "Name": "Cut last node", "Text": "Fix an error caused by attempting to use the Edit > Cut command when there is only one node." }, "format": "BULLETS", "uid": "bdc8628ec2bd11e889e57054d2175f18" }, { "children": [], "data": { "Name": "MacPorts reference", "Text": "References to a macOS port on MacPorts were added to the System Requirements and Installation documentation." }, "format": "BULLETS", "uid": "c1f8dca5dc9511ea8f76ac675dac20af" }, { "children": [], "data": { "Name": "Filter view icon", "Text": "Fixed a problem with the filter view when the tree icon is set to none." }, "format": "BULLETS", "uid": "c31396d6813411f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Windows binaries", "Text": "Update the libraries used to build the Windows binaries to Python 3.10 and Qt/PyQt 5.15. Note that this eliminates support for Windows 7." }, "format": "BULLETS", "uid": "c5c45e3e2d4411eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Russian translation", "Text": "Add a Russian translation of the GUI and the help files (thanks to Andrew Trofimov)." }, "format": "BULLETS", "uid": "c771aa162ca911eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "German translation", "Text": "Update the German GUI translation (thanks to Karsten)." }, "format": "BULLETS", "uid": "c8eb2e4e2ca911eda95c54b2039ee1f3" }, { "children": [], "data": { "Name": "Data editor hover", "Text": "By default, the edit boxes in the data edit view now activate when the mouse hovers over them. This eliminates the need to click to activate them. This feature can be disabled in general options if desired." }, "format": "BULLETS", "uid": "cd28e024bb0211e79c553417ebd53aeb" }, { "children": [], "data": { "Name": "Unlimited data editor height option", "Text": "Add a general option to extend the height of data editors with long text content. The default setting (limit the height to the window size) is unchanged. The new option uses the view scroll bars to access the full text length." }, "format": "BULLETS", "uid": "cef1d9fee5de11e998dea44cc8e97404" }, { "children": [], "data": { "Name": "Math field recalculation", "Text": "Perform a more complete recalculation of math fields after certain operations." }, "format": "BULLETS", "uid": "cf9c139fdc8e11ea8261ac675dac20af" }, { "children": [], "data": { "Name": "TreeLine 2 import / export", "Text": "Import and export filters are provided for older TreeLine version 2.x and 1.x files. The older files can be opened using the standard \"File > Open\" command." }, "format": "BULLETS", "uid": "d1d8e56eba4011e784ab3417ebd53aeb" }, { "children": [], "data": { "Name": "MacPorts", "Text": "There is a third-party port available on MacPorts." }, "format": "BULLETS", "uid": "d8a76c1fdc9411eaab2dac675dac20af" }, { "children": [], "data": { "Name": "Enable add child", "Text": "Make the Add Child command available after filtering has ended." }, "format": "BULLETS", "uid": "d9119485dc8711ea92dcac675dac20af" }, { "children": [ "ff3f7c98481e11e989f27054d2175f18", "db25ce66481e11e989f27054d2175f18" ], "data": { "Name": "March 17, 2019 - Release 3.1.1 (stable release)" }, "format": "HEADINGS", "uid": "db25cd62481e11e989f27054d2175f18" }, { "children": [ "e3690592481f11e989f27054d2175f18", "84b24010482211e989f27054d2175f18", "db25cf60481e11e989f27054d2175f18", "95d970aa481f11e989f27054d2175f18", "25ab9320482011e989f27054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "db25ce66481e11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Math equation with copied type", "Text": "Fix problems defining a math field equation on a recently copied data type." }, "format": "BULLETS", "uid": "db25cf60481e11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Sort root nodes", "Text": "The Sort command now properly sorts multiple root nodes when sorting the entire tree." }, "format": "BULLETS", "uid": "dc700fb4c24211e8b88dd66a6ab671cb" }, { "children": [], "data": { "Name": "Customize colors", "Text": "Add a more flexible tool for customizing GUI colors." }, "format": "BULLETS", "uid": "dca5b84fdc8a11eab098ac675dac20af" }, { "children": [], "data": { "Name": "Multi-level CSV import / export", "Text": "New forms of CSV table text imports and exports can work with multiple levels of child nodes, preserving the tree structure. The first column of the table includes a level number that is incremented for child relationships." }, "format": "BULLETS", "uid": "dd22e382334111e894e6d66a6ab671cb" }, { "children": [], "data": { "Name": "CSV import error", "Text": "Avoid a traceback error message when attempting to import a CSV file with a bad header row." }, "format": "BULLETS", "uid": "df7baad6fe8011edbb2654b2039ee1f3" }, { "children": [], "data": { "Name": "Dark mode printing", "Text": "Fix printing problems when using the dark theme." }, "format": "BULLETS", "uid": "e3690592481f11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Error after empty filter", "Text": "Avoid problems showing the tree view after closing a filter command that found no matches." }, "format": "BULLETS", "uid": "e46163b4334b11e88512d66a6ab671cb" }, { "children": [], "data": { "Name": "Deletion errors", "Text": "Several errors occurring when deleting or removing nodes have been fixed. These include problems when the mouse is pre-highlighting descendant nodes and when nodes to be deleted are selected in a separate window." }, "format": "BULLETS", "uid": "e4fc680a786911e899d3a44cc8e97404" }, { "children": [], "data": { "Name": "Breadcrumb view", "Text": "A new breadcrumb view pane above the other panes shows a sequence of ancestor titles for a selected node. The ancestors can be clicked to select them. For cloned nodes, multiple lines provide links to each instance's ancestor sequence." }, "format": "BULLETS", "uid": "e6ad9f6eba4311e796bd3417ebd53aeb" }, { "children": [], "data": { "Name": "Windows binary", "Text": "The Windows binary is now built using updated libraries (Qt 5.11 and PyQt 5.11)." }, "format": "BULLETS", "uid": "e7776f4da14511e88aefa44cc8e97404" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is the first stable release of a major TreeLine rewrite. It includes all of the new features shown below in the 2.1.x and 2.9.x development series." }, "format": "BULLETS", "uid": "e8e10d32a14311e8ab90a44cc8e97404" }, { "children": [ "e8e10d34a14311e899cca44cc8e97404", "e8e10d38a14311e8a0c3a44cc8e97404", "e8e10d37a14311e8b0b3a44cc8e97404" ], "data": { "Name": "August 19, 2018 - Release 3.0.0 (new stable release)" }, "format": "HEADINGS", "uid": "e8e10d33a14311e88e24a44cc8e97404" }, { "children": [ "e8e10d32a14311e8ab90a44cc8e97404", "e8e10d35a14311e8aca9a44cc8e97404", "e8e10d36a14311e8b832a44cc8e97404" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "e8e10d34a14311e899cca44cc8e97404" }, { "children": [], "data": { "Name": "Compatibility", "Text": "TreeLine files now use a JSON format in place of the old XML format. This provides more flexibility for structuring new features like cloned nodes and multiple root nodes. A new file extension (\".trln) helps to distinguish files with the new format. Import and export filters are provided for older TreeLine version 2.x and 1.x files. The older files can be opened using the standard \"File > Open\" command." }, "format": "BULLETS", "uid": "e8e10d35a14311e8aca9a44cc8e97404" }, { "children": [], "data": { "Name": "Translations", "Text": "A GUI translations is available in German. All other translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "e8e10d36a14311e8b832a44cc8e97404" }, { "children": [ "e7776f4da14511e88aefa44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "e8e10d37a14311e8b0b3a44cc8e97404" }, { "children": [ "e8e10d3ca14311e8b71da44cc8e97404" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "e8e10d38a14311e8a0c3a44cc8e97404" }, { "children": [], "data": { "Name": "Default font", "Text": "The default font for the application can now be set in Tools > Customize Fonts. This is useful for enlarging fonts on some systems with high screen resolutions. Options still exist to individually specify tree view, output view and editor fonts." }, "format": "BULLETS", "uid": "e8e10d3ca14311e8b71da44cc8e97404" }, { "children": [], "data": { "Name": "Add modified flag", "Text": "Add an asterisk after the file name in the title bar if a file has been modified." }, "format": "BULLETS", "uid": "ea0c9b24e79911e98abe7054d2175f18" }, { "children": [], "data": { "Name": "Category command disable", "Text": "Avoid problems running data category-based commands on selections without any child nodes." }, "format": "BULLETS", "uid": "edd50b80334c11e8b5f5d66a6ab671cb" }, { "children": [], "data": { "Name": "Initial field values", "Text": "Fixed errors occurring when field types are changed after initial default values have been set." }, "format": "BULLETS", "uid": "f011a5d8786911e8ace3a44cc8e97404" }, { "children": [], "data": { "Name": "Cloned nodes", "Text": "Nodes that are duplicated by cloning show up as separate clickable paths in the upper breadcrumb view." }, "format": "BULLETS", "uid": "f08b97be792b11e88588a44cc8e97404" }, { "children": [ "f16f7f70a25a11e7b7c67054d2175f18", "f16f87b8a25a11e7b7c67054d2175f18", "f16fbef4a25a11e7b7c67054d2175f18", "f16fc7aaa25a11e7b7c67054d2175f18", "f16fd236a25a11e7b7c67054d2175f18", "f16fe6fea25a11e7b7c67054d2175f18", "f1703d8ea25a11e7b7c67054d2175f18", "f1713464a25a11e7b7c67054d2175f18" ], "data": { "Name": "TreeLine Documentation" }, "format": "HEADINGS", "uid": "f16f7d90a25a11e7b7c67054d2175f18" }, { "children": [ "f16f82aea25a11e7b7c67054d2175f18", "f16f8498a25a11e7b7c67054d2175f18", "f16f85b0a25a11e7b7c67054d2175f18", "f16f86aaa25a11e7b7c67054d2175f18" ], "data": { "Name": "Introduction" }, "format": "HEADINGS", "uid": "f16f7f70a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Version", "Text": "This document covers TreeLine, Version 3.2.1, a stable release, dated September 27, 2025 by Doug Bell." }, "format": "PARAGRAPH", "uid": "f16f82aea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Why TreeLine?", "Text": "Do you have lots of sticky notes lying around with various useful information jotted down? Or many lists of books, movies, links, website logins, personal contacts, or things to do? Can you find them when you need them? Well, I often couldn't. So here's my answer." }, "format": "PARAGRAPH", "uid": "f16f8498a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Outliner vs. database", "Text": "TreeLine is both an outliner and a small database. It stores almost any kind of information. A tree structure makes it easy to keep things organized. And each node in the tree can contain several fields, forming a database. The output format for each node can be defined, and the output can be shown on the screen, printed, or exported to HTML or text." }, "format": "PARAGRAPH", "uid": "f16f85b0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "License", "Text": "Since I'm not in the software business, I'm making this program free for anyone to use, distribute and modify, as long as it stays non-proprietary. TreeLine is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either Version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. See the LICENSE file provided with this program for more information." }, "format": "PARAGRAPH", "uid": "f16f86aaa25a11e7b7c67054d2175f18" }, { "children": [ "f16f8aeca25a11e7b7c67054d2175f18", "f16f9654a25a11e7b7c67054d2175f18", "f16f9c44a25a11e7b7c67054d2175f18", "f16fa040a25a11e7b7c67054d2175f18", "f16fa31aa25a11e7b7c67054d2175f18", "f16fa806a25a11e7b7c67054d2175f18", "f16fadf6a25a11e7b7c67054d2175f18", "f16fb1dea25a11e7b7c67054d2175f18", "f16fb90ea25a11e7b7c67054d2175f18" ], "data": { "Name": "Features" }, "format": "HEADINGS", "uid": "f16f87b8a25a11e7b7c67054d2175f18" }, { "children": [ "f16f9050a25a11e7b7c67054d2175f18", "f16f921ca25a11e7b7c67054d2175f18", "f16f932aa25a11e7b7c67054d2175f18", "f16f9424a25a11e7b7c67054d2175f18", "f16f9550a25a11e7b7c67054d2175f18" ], "data": { "Name": "General" }, "format": "BULLET_HEADING", "uid": "f16f8aeca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Store information", "Text": "Stores almost any type of information, including plain text, rich text, HTML, numbers, dates, times, booleans, URLs, etc." }, "format": "BULLETS", "uid": "f16f9050a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Tree structure", "Text": "The tree structure helps keep things organized." }, "format": "BULLETS", "uid": "f16f921ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Fields", "Text": "Each node can have several fields that form a mini-database." }, "format": "BULLETS", "uid": "f16f932aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Node types", "Text": "Several node types, with different sets of fields, can be included in one file." }, "format": "BULLETS", "uid": "f16f9424a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Output format", "Text": "The node format, including fields, output lines, formatting and tree-view icon, can be defined for each node type." }, "format": "BULLETS", "uid": "f16f9550a25a11e7b7c67054d2175f18" }, { "children": [ "f16f9744a25a11e7b7c67054d2175f18", "f16f9834a25a11e7b7c67054d2175f18", "f16f992ea25a11e7b7c67054d2175f18", "f16f9a32a25a11e7b7c67054d2175f18", "f16f9b36a25a11e7b7c67054d2175f18", "b1b5d434b32911e780fd3417ebd53aeb" ], "data": { "Name": "Views" }, "format": "BULLET_HEADING", "uid": "f16f9654a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Tree view", "Text": "The left-hand view shows an indented, expandable list of titles" }, "format": "BULLETS", "uid": "f16f9744a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Right-hand views", "Text": "The right-hand view can show one of three views - for showing output, editing node data and editing node titles." }, "format": "BULLETS", "uid": "f16f9834a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Show parent and children", "Text": "The right-hand view is normally split to show data from the parent node and its children." }, "format": "BULLETS", "uid": "f16f992ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Show multiple selection", "Text": "If multiple nodes are selected, the right-hand view shows all of their data." }, "format": "BULLETS", "uid": "f16f9a32a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Show descendant output", "Text": "The output view can be set to show indented output from all descendant nodes." }, "format": "BULLETS", "uid": "f16f9b36a25a11e7b7c67054d2175f18" }, { "children": [ "f16f9d2aa25a11e7b7c67054d2175f18", "f16f9e2ea25a11e7b7c67054d2175f18", "f16f9f3ca25a11e7b7c67054d2175f18" ], "data": { "Name": "Navigation" }, "format": "BULLET_HEADING", "uid": "f16f9c44a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Find commands", "Text": "Find commands can search node data for text matches or for more specific rules." }, "format": "BULLETS", "uid": "f16f9d2aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Filtering", "Text": "Filtering commands show only matching nodes in a flat left-hand view." }, "format": "BULLETS", "uid": "f16f9e2ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Toggle selections", "Text": "Previous and next selection commands toggle selections to quickly move between parts of the tree." }, "format": "BULLETS", "uid": "f16f9f3ca25a11e7b7c67054d2175f18" }, { "children": [ "f16fa130a25a11e7b7c67054d2175f18", "5c1d58ac792a11e8b78ca44cc8e97404", "f16fa220a25a11e7b7c67054d2175f18" ], "data": { "Name": "Formatting" }, "format": "BULLET_HEADING", "uid": "f16fa040a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Configuration dialog", "Text": "The dialog for data type configuration has several tabs to easily set all type, field and output parameters." }, "format": "BULLETS", "uid": "f16fa130a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Format copies", "Text": "Formatting information can be copied from another TreeLine file." }, "format": "BULLETS", "uid": "f16fa220a25a11e7b7c67054d2175f18" }, { "children": [ "f16fa40aa25a11e7b7c67054d2175f18", "f16fa504a25a11e7b7c67054d2175f18", "f16fa5fea25a11e7b7c67054d2175f18", "f16fa70ca25a11e7b7c67054d2175f18" ], "data": { "Name": "File Handling" }, "format": "BULLET_HEADING", "uid": "f16fa31aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Undo/redo", "Text": "Undo and redo commands are available for all modifying operations." }, "format": "BULLETS", "uid": "f16fa40aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File formats", "Text": "TreeLine files use a JSON format, with options for automatically compressing or encrypting the files." }, "format": "BULLETS", "uid": "f16fa504a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Document templates", "Text": "Document templates for new files are preformatted to cover basic needs." }, "format": "BULLETS", "uid": "f16fa5fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Printing", "Text": "The formatted output can be printed with parent/child lines, headers and footers." }, "format": "BULLETS", "uid": "f16fa70ca25a11e7b7c67054d2175f18" }, { "children": [ "f16fa8f6a25a11e7b7c67054d2175f18", "31304c06792b11e888cfa44cc8e97404", "f16fa9f0a25a11e7b7c67054d2175f18", "9bd80f34b32b11e7be613417ebd53aeb", "f16faaf4a25a11e7b7c67054d2175f18", "f16fabf8a25a11e7b7c67054d2175f18", "f16facf2a25a11e7b7c67054d2175f18" ], "data": { "Name": "File Import and Export" }, "format": "BULLET_HEADING", "uid": "f16fa806a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML export", "Text": "The data can be exported to single or multiple HTML files with optional navigation panes." }, "format": "BULLETS", "uid": "f16fa8f6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Text import/export", "Text": "Plain text, tab-indented text and delimited table files can be imported and exported." }, "format": "BULLETS", "uid": "f16fa9f0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Bookmark import/export", "Text": "Mozilla and XBEL format bookmark files can be imported and exported." }, "format": "BULLETS", "uid": "f16faaf4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Generic XML import/export", "Text": "Generic XML files can be imported and exported, allowing TreeLine to function as a crude XML editor." }, "format": "BULLETS", "uid": "f16fabf8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "ODF import/export", "Text": "ODF text documents can be imported and exported as outlines." }, "format": "BULLETS", "uid": "f16facf2a25a11e7b7c67054d2175f18" }, { "children": [ "f16faee6a25a11e7b7c67054d2175f18", "f16fafe0a25a11e7b7c67054d2175f18", "f16fb0daa25a11e7b7c67054d2175f18", "f08b97be792b11e88588a44cc8e97404" ], "data": { "Name": "Linking" }, "format": "BULLET_HEADING", "uid": "f16fadf6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Internal links", "Text": "Internal link fields select a linked node when clicked." }, "format": "BULLETS", "uid": "f16faee6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "External links", "Text": "External link fields can be used to open URLs in web browsers." }, "format": "BULLETS", "uid": "f16fafe0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Embedded links", "Text": "Both internal and external links can be embedded into text fields." }, "format": "BULLETS", "uid": "f16fb0daa25a11e7b7c67054d2175f18" }, { "children": [ "f16fb2cea25a11e7b7c67054d2175f18", "f16fb3c8a25a11e7b7c67054d2175f18", "f16fb4eaa25a11e7b7c67054d2175f18", "f16fb5e4a25a11e7b7c67054d2175f18", "5f12f768b32c11e7a41a3417ebd53aeb", "f16fb6dea25a11e7b7c67054d2175f18", "f16fb7f6a25a11e7b7c67054d2175f18" ], "data": { "Name": "Data Manipulation" }, "format": "BULLET_HEADING", "uid": "f16fb1dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sorting", "Text": "Nodes can be sorted by title or by predefined key fields." }, "format": "BULLETS", "uid": "f16fb2cea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math Fields", "Text": "Math fields can be defined that automatically calculate their contents based on numerical values in other nodes." }, "format": "BULLETS", "uid": "f16fb3c8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Numbering", "Text": "Numbering fields can be defined and automatically updated." }, "format": "BULLETS", "uid": "f16fb4eaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional types", "Text": "A node's icon and output format can be changed conditionally based on its data." }, "format": "BULLETS", "uid": "f16fb5e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spell check", "Text": "Text data can be spell checked (requires an external program - see the System Requirements section)." }, "format": "BULLETS", "uid": "f16fb6dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Arranging data", "Text": "Data can be automatically re-arranged using categories from data fields." }, "format": "BULLETS", "uid": "f16fb7f6a25a11e7b7c67054d2175f18" }, { "children": [ "f16fba08a25a11e7b7c67054d2175f18", "f16fbb02a25a11e7b7c67054d2175f18", "f16fbc06a25a11e7b7c67054d2175f18", "f16fbd00a25a11e7b7c67054d2175f18" ], "data": { "Name": "Customization" }, "format": "BULLET_HEADING", "uid": "f16fb90ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Customization", "Text": "There are many options for customizing both general and file-based attributes." }, "format": "BULLETS", "uid": "f16fba08a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Shortcuts and toolbars", "Text": "There are editors for keyboard shortcuts and toolbar commands." }, "format": "BULLETS", "uid": "f16fbb02a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Fonts", "Text": "Fonts used in the GUI, editors and output views can be customized." }, "format": "BULLETS", "uid": "f16fbc06a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Languages", "Text": "The user interface is available in simplified Chinese, English, German, Russian and Spanish. Translations into other languages are TBD." }, "format": "BULLETS", "uid": "f16fbd00a25a11e7b7c67054d2175f18" }, { "children": [ "f16fbfeea25a11e7b7c67054d2175f18", "f16fc4bca25a11e7b7c67054d2175f18", "460699ebdc9411ea89afac675dac20af" ], "data": { "Name": "System Requirements" }, "format": "HEADINGS", "uid": "f16fbef4a25a11e7b7c67054d2175f18" }, { "children": [ "f16fc0d4a25a11e7b7c67054d2175f18", "f16fc1cea25a11e7b7c67054d2175f18", "f16fc2c8a25a11e7b7c67054d2175f18", "f16fc3c2a25a11e7b7c67054d2175f18" ], "data": { "Name": "Linux" }, "format": "BULLET_HEADING", "uid": "f16fbfeea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Python", "Text": "Python (Version 3.9 or higher)" }, "format": "BULLETS", "uid": "f16fc0d4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Qt", "Text": "QT (Version 6.4 or higher)" }, "format": "BULLETS", "uid": "f16fc1cea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "PyQt", "Text": "PyQt (Version 6.4 or higher)" }, "format": "BULLETS", "uid": "f16fc2c8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spell check", "Text": "If spell checking is desired, either aspell, ispell or hunspell are required" }, "format": "BULLETS", "uid": "f16fc3c2a25a11e7b7c67054d2175f18" }, { "children": [ "f16fc5aca25a11e7b7c67054d2175f18", "f16fc6b0a25a11e7b7c67054d2175f18" ], "data": { "Name": "Windows" }, "format": "BULLET_HEADING", "uid": "f16fc4bca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Binary", "Text": "Should run on any computer running Windows 10 or 11." }, "format": "BULLETS", "uid": "f16fc5aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spell check", "Text": "If spell checking is desired, an external program is required. Either aspell, ispell or hunspell must be installed." }, "format": "BULLETS", "uid": "f16fc6b0a25a11e7b7c67054d2175f18" }, { "children": [ "f16fc89aa25a11e7b7c67054d2175f18", "f16fcc96a25a11e7b7c67054d2175f18", "611e03ffdc9411ea930eac675dac20af" ], "data": { "Name": "Installation" }, "format": "HEADINGS", "uid": "f16fc7aaa25a11e7b7c67054d2175f18" }, { "children": [ "f16fc98aa25a11e7b7c67054d2175f18", "f16fcaa2a25a11e7b7c67054d2175f18", "f16fcb9ca25a11e7b7c67054d2175f18" ], "data": { "Name": "Linux" }, "format": "HEADINGS", "uid": "f16fc89aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Basic installation", "Text": "Extract the source files from the treeline tar file, then change to the TreeLine directory in a terminal. For a basic installation, simply execute the following command as root: \"python install.py\"." }, "format": "PARAGRAPH", "uid": "f16fc98aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Python 3", "Text": "If your distribution defaults to Python 2.x, you may need to substitute \"python3\" for \"python\" in these commands." }, "format": "PARAGRAPH", "uid": "f16fcaa2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Install options", "Text": "To see all install options, use: \"python install.py -h\". To install TreeLine with a different prefix (the default is /usr/local), use: \"python install.py -p /prefix/path\". To skip dependency checks, use: \"python install.py -x\"." }, "format": "PARAGRAPH", "uid": "f16fcb9ca25a11e7b7c67054d2175f18" }, { "children": [ "f16fcf3ea25a11e7b7c67054d2175f18", "f16fd042a25a11e7b7c67054d2175f18", "f16fd132a25a11e7b7c67054d2175f18" ], "data": { "Name": "Windows" }, "format": "HEADINGS", "uid": "f16fcc96a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "All users", "Text": "To install for all users, execute the \"TreeLine-x.x.x-install-all.exe\" file. Administrator permissions are required." }, "format": "PARAGRAPH", "uid": "f16fcf3ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Single user", "Text": "To install for a single user (administrator rights are not required), execute the \"TreeLine-x.x.x-install-user.exe\" file." }, "format": "PARAGRAPH", "uid": "f16fd042a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Portable install", "Text": "For a portable install, execute the \"TreeLine-x.x.x-install-user.exe\" file. The file association, shortcuts and uninstaller tasks should be unchecked. When TreeLine starts and prompts for the config file location, choose the program directory option." }, "format": "PARAGRAPH", "uid": "f16fd132a25a11e7b7c67054d2175f18" }, { "children": [ "f16fd326a25a11e7b7c67054d2175f18", "f16fdccca25a11e7b7c67054d2175f18", "f16fe0b4a25a11e7b7c67054d2175f18", "f16fe3fca25a11e7b7c67054d2175f18" ], "data": { "Name": "Basic Usage" }, "format": "HEADINGS", "uid": "f16fd236a25a11e7b7c67054d2175f18" }, { "children": [ "f16fd682a25a11e7b7c67054d2175f18", "28f8844ab58711e79d173417ebd53aeb", "f16fd858a25a11e7b7c67054d2175f18", "f16fd9aca25a11e7b7c67054d2175f18", "f16fdabaa25a11e7b7c67054d2175f18", "f16fdbc8a25a11e7b7c67054d2175f18" ], "data": { "Name": "Views" }, "format": "HEADINGS", "uid": "f16fd326a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Tree View", "Text": "The left-hand view shows a tree of node titles. Parent nodes can be opened and closed to display or hide their indented descendant nodes. Clicking on an already selected node allows the title to be edited. Right-click context menus are available for commonly used functions." }, "format": "HEAD_PARA", "uid": "f16fd682a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Right-hand Views", "Text": "The right pane is tabbed to show one of three different views of the data. The \"Data Output\" view shows the formatted text, the \"Data Edit\" view shows text edit boxes, and the \"Title List\" view shows an editable list of node titles.
\n
\nWhen a parent node is selected in the tree, the right view will default to showing information about the selected node in an upper pane and information about the selected node's children in a lower pane. The \"View > Show Child Pane\" command will toggle the display of the child nodes. If the selected node has no children, the view will show a single pane with information about the selected node only.
\n
\nWhen multiple nodes are selected in the tree (by holding down the shift or Ctrl keys while clicking), the right view will not display any child node information. It will instead show information about every selected node.
\n
\nWhen no nodes are selected in the tree (by clicking on a blank area or Ctrl clicking to unselect), the right view will show information about the top-level (root) nodes." }, "format": "HEAD_PARA", "uid": "f16fd858a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data Output View", "Text": "The \"Data Output\" view shows formatted output text. It cannot be edited from this view.
\n
\nWhen the \"View > Show Output Descendants\" command is toggled, the \"Data Output\" view will show an indented list with information about every descendant of a single selected node." }, "format": "HEAD_PARA", "uid": "f16fd9aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data Edit View", "Text": "The \"Data Edit\" view shows a text edit box for each data field within a node. It also shows the node types and the node titles. The types of edit boxes vary based on the field type. Some are just text editors, while others (such as choice fields, date fields, links, etc.) have pull-down menus or dialogs." }, "format": "HEAD_PARA", "uid": "f16fdabaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Title List View", "Text": "The \"Title List\" view shows a list of node titles that can be modified using typical text editor methods. If a new line is typed, a new node is created with that title. If a line is deleted, the corresponding node is removed from the tree." }, "format": "HEAD_PARA", "uid": "f16fdbc8a25a11e7b7c67054d2175f18" }, { "children": [ "f16fddbca25a11e7b7c67054d2175f18", "f16fdeb6a25a11e7b7c67054d2175f18", "997af664b58811e7ac243417ebd53aeb", "f16fdfb0a25a11e7b7c67054d2175f18" ], "data": { "Name": "Editing" }, "format": "HEADINGS", "uid": "f16fdccca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Node Menu", "Text": "The commands in the \"Node\" menu operate on the selected nodes in the left tree view. There are commands to add or insert nodes, rename node titles and delete nodes. There are also commands to rearrange the tree by changing indent levels or moving nodes up or down. For many of the commands, the descendants of the selected nodes are also affected." }, "format": "HEAD_PARA", "uid": "f16fddbca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Edit Menu", "Text": "The edit menu includes undo and redo commands that can fix problems. Cut, copy and paste commands can operate either on text in the right-hand view (if selected or active) or to tree nodes." }, "format": "HEAD_PARA", "uid": "f16fdeb6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Shortcuts", "Text": "There are several shortcuts for use in tree editing. Drag and drop will move (or copy if the Ctrl button is held) nodes. Clicking on a selected node will rename it. Pressing the delete key will remove the selected nodes. If desired, these shortcuts can be disabled in \"Tools > General Options\"." }, "format": "HEAD_PARA", "uid": "f16fdfb0a25a11e7b7c67054d2175f18" }, { "children": [ "f16fe1cca25a11e7b7c67054d2175f18", "f16fe2c6a25a11e7b7c67054d2175f18" ], "data": { "Name": "Files" }, "format": "HEADINGS", "uid": "f16fe0b4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Templates", "Text": "When starting a new file, a dialog box offers a choice of templates. The default has only a single text field for each node that contains the title. The Long Text template adds a second long text field for more output text. Other templates have various fields for contacts, book lists and to-do lists." }, "format": "HEAD_PARA", "uid": "f16fe1cca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sample Files", "Text": "Various TreeLine sample files can be opened by using the \"File > Open Sample\" command. These have more detail and example content than the new file templates." }, "format": "HEAD_PARA", "uid": "f16fe2c6a25a11e7b7c67054d2175f18" }, { "children": [ "f16fe4eca25a11e7b7c67054d2175f18", "f16fe5f0a25a11e7b7c67054d2175f18" ], "data": { "Name": "Data Types" }, "format": "HEADINGS", "uid": "f16fe3fca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Node Types", "Text": "Multiple node data types can be defined in a TreeLine file. Each can contain different data fields and have different output formats. See the template and sample files for examples. Nodes can be set to a specific type using the \"Data > Set Node Type\" command." }, "format": "HEAD_PARA", "uid": "f16fe4eca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Type Config", "Text": "The \"Data > Configure Data Types\" command is used to modify node data types, fields and output formatting. Refer to the Detailed Usage section of the full documentation for details." }, "format": "HEAD_PARA", "uid": "f16fe5f0a25a11e7b7c67054d2175f18" }, { "children": [ "f16fe7e4a25a11e7b7c67054d2175f18", "f16fed0ca25a11e7b7c67054d2175f18", "f16ff2f2a25a11e7b7c67054d2175f18", "f1700936a25a11e7b7c67054d2175f18", "f1700f58a25a11e7b7c67054d2175f18", "f170146ca25a11e7b7c67054d2175f18", "f1701caaa25a11e7b7c67054d2175f18", "f170207ea25a11e7b7c67054d2175f18", "f170256aa25a11e7b7c67054d2175f18", "f1702c4aa25a11e7b7c67054d2175f18", "f170335ca25a11e7b7c67054d2175f18" ], "data": { "Name": "Detailed Usage" }, "format": "HEADINGS", "uid": "f16fe6fea25a11e7b7c67054d2175f18" }, { "children": [ "f16fe8dea25a11e7b7c67054d2175f18", "f16fe9e2a25a11e7b7c67054d2175f18", "f16feaf0a25a11e7b7c67054d2175f18", "f16fec08a25a11e7b7c67054d2175f18" ], "data": { "Name": "Tree Navigation and Search" }, "format": "HEADINGS", "uid": "f16fe7e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Keyboard Shortcuts", "Text": "There are several keyboard commands that can be used for tree navigation. The up and down arrow keys move the selection. The left and right arrows open and close the current node. The \"Home\", \"End\", \"Page Up\" and \"Page Down\" keys can be used to move quickly through the tree.
\n
\nAnother way to move through the tree is to type the first letter of a visible node title. Hitting the letter again highlights to the next possibility." }, "format": "HEAD_PARA", "uid": "f16fe8dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Selection", "Text": "Multiple nodes can be selected by holding down the CTRL or the SHIFT key when changing the active node. Individual nodes are added or removed from the selection when the CTRL key is held. The selection of all nodes between the old and new active nodes are toggled when SHIFT is held. The active node can be changed by using the mouse or by using any of the keyboard navigation methods.
\n
\nThe \"View > Previous Selection\" and \"View > Next Selection\" commands can be used to toggle through a history of selections, allowing faster navigation through the tree." }, "format": "HEAD_PARA", "uid": "f16fe9e2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Searching", "Text": "The \"Tools > Find Text\" command will search for text within the tree structure. The dialog box has options for searching all of the node data or only the node titles. There are also options for how to interpret the search text. Key words will match nodes with the search words found anywhere in the node. Key full words will only match complete words anywhere in the node. Full phrase will only match the complete phrase in the proper sequence. Finally, the regular expression option will search using Python regular expressions.
\n
\nThe \"Tools > Conditional Find\" command will search in particular node types and node fields. Various comparison operators can be selected to exactly match, to match a greater or lesser value, or part of the value. And the True/False operators give the same result regardless of the values. In general, the value is interpreted using the edit format for special field types. Multiple rules can be added, connected with logical \"and\" or \"or\" operators. The \"All Types\" option makes fields from every type are available, so that multiple node types to be part of the same search. The condition will be false for node types that do not contain that field name.
\n
\nThere is also a quick, incremental search of node titles. By default, it's bound to ctrl+/. Then, matching titles are found as the search string is typed. The F3 and shift+F3 keys can be used to go to the next or previous matches, respectively." }, "format": "HEAD_PARA", "uid": "f16feaf0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Filtering", "Text": "There are two filtering commands, \"Tools > Text Filter\" and \"Tools > Conditional Filter\". They work like the corresponding search commands above, except that they show all of the matching nodes in a flat list that replaces the tree view. The nodes can be selected and edited from this view. Use the \"End Filter\" button to restore the full tree view.
\n
\nSearches for Conditional Find and Conditional Filter can be saved in the dialog boxes and loaded again at another time." }, "format": "HEAD_PARA", "uid": "f16fec08a25a11e7b7c67054d2175f18" }, { "children": [ "f16fedfca25a11e7b7c67054d2175f18", "f16feef6a25a11e7b7c67054d2175f18", "f16feffaa25a11e7b7c67054d2175f18", "f16ff0f4a25a11e7b7c67054d2175f18", "f16ff1e4a25a11e7b7c67054d2175f18" ], "data": { "Name": "Defining Node Types" }, "format": "HEADINGS", "uid": "f16fed0ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Type List", "Text": "The \"Type List\" is the first tab of the \"Data > Configure Types Dialog\". The list of data types can be modified by the buttons on the right. New types can be added, and existing types can be copied, renamed or deleted." }, "format": "HEAD_PARA", "uid": "f16fedfca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Type Config", "Text": "\"Type Config\" is the second tab of the Configure Types Dialog. It contains a selection for the default child type. If set, this will be the initial type used for new children with this type of parent. If set to \"[None]\", children will default to either the type of their siblings or their parent.
\n
\nThe \"Change Icon\" button allows the selection of a custom tree icon for this data type. The \"Clear Select\" button on the icon dialog can be used to set the icon to \"None\", so that no icon will be displayed for this type. To avoid showing any tree icons, the \"Show icons in the tree view\" general option can be unset.
\n
\nThere are also options here for adding blanks lines between nodes, allowing HTML tags in the common format text, and changing the output to add bullets or tables." }, "format": "HEAD_PARA", "uid": "f16feef6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Field List", "Text": "The \"Field List\" is the third tab of the Configure Types Dialog. The list of fields within a data type can be modified by using the buttons on the right. New fields can be added, and existing fields can be moved, renamed or deleted. Sort keys can also be defined to specify the fields that are compared when nodes are sorted." }, "format": "HEAD_PARA", "uid": "f16feffaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Field Config", "Text": "\"Field Config\" is the fourth tab of the Configure Types Dialog. The field type and its output format string can be set, if applicable to the field. Extra prefix and suffix text to be output with the field can also be set, and a default field value for new nodes can be entered. The number of lines displayed in the editor for the field can also be specified. Finally, an option to evaluate HTML tags can be set to recognize HTML tags in Choice, AutoChoice, Combination, AutoCombination and RegularExpression fields. If this is set, special characters (angled brackets and quotation marks) will need to be manually escaped to show up in the field text." }, "format": "HEAD_PARA", "uid": "f16ff0f4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Output", "Text": "\"Output\" is the last tab of the Configure Types Dialog. The left half of the dialog shows the fields. The right half shows the formatting for the title (used for the node text in the tree view) and the node output. The formatting consists of text lines with embedded fields. The fields are shown as \"{*field_name*}\". The fields that are selected in the list (multiple fields can be selected by holding Ctrl or Shift keys while clicking) can be added to a format at the cursor position with the \">>\" keys. The field reference at the cursor can be removed with the \"<<\" keys." }, "format": "HEAD_PARA", "uid": "f16ff1e4a25a11e7b7c67054d2175f18" }, { "children": [ "f16ff3e2a25a11e7b7c67054d2175f18", "f16ff4dca25a11e7b7c67054d2175f18", "f16ff5f4a25a11e7b7c67054d2175f18", "f16ff7c0a25a11e7b7c67054d2175f18", "f16ff8f6a25a11e7b7c67054d2175f18", "f16ff9faa25a11e7b7c67054d2175f18", "f17005f8a25a11e7b7c67054d2175f18", "f1700710a25a11e7b7c67054d2175f18", "f16ffc02a25a11e7b7c67054d2175f18", "f16ffd06a25a11e7b7c67054d2175f18", "f16ffe14a25a11e7b7c67054d2175f18", "f16ffb08a25a11e7b7c67054d2175f18", "f16fff18a25a11e7b7c67054d2175f18", "f1700008a25a11e7b7c67054d2175f18", "f1700102a25a11e7b7c67054d2175f18", "f1700206a25a11e7b7c67054d2175f18", "f1700300a25a11e7b7c67054d2175f18", "f1700404a25a11e7b7c67054d2175f18", "f17004fea25a11e7b7c67054d2175f18", "f170081ea25a11e7b7c67054d2175f18" ], "data": { "Name": "Field Types" }, "format": "HEADINGS", "uid": "f16ff2f2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Field Options", "Text": "The field type and options are set in the \"Field Config\" tab of the \"Data > Configure Types Dialog\". The many different field types are described in the paragraphs below.
\n
\nSeveral of the field types use a formatting string to define their output. For a list of available formatting characters, use the \"Format Help\" button. Entries in the data editor which do not match the format will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with \"#####\"." }, "format": "HEAD_PARA", "uid": "f16ff3e2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Text Type", "Text": "The default field type is a text field. It is the most commonly used field. These fields are edited using edit boxes in the data editor view. There are several commands in the Format menu (and also in the context menu) for setting the font style and adding external or internal links. The edit box height expands when re-displayed after adding several lines of text. The minimum edit box height can also be set explicitly in the \"Field Config\" tab." }, "format": "HEAD_PARA", "uid": "f16ff4dca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML Text Type", "Text": "This type allows simple HTML tags to be used in the text. Commonly used tags include \"<b>bold</b>\", \"<u>underline</u>\", \"line break<br/>\", \"horizontal line<hr/>\", and various font tags. Complex block tags should generally be avoided. Carriage returns are ignored, and non-escaped \"<\", \">\" and \"&\" symbols do not display. " }, "format": "HEAD_PARA", "uid": "f16ff5f4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "One Line Text Type", "Text": "This type restricts the text length to a single line. It does not allow carriage returns but does not restrict line wrapping of a single long line." }, "format": "HEAD_PARA", "uid": "f16ff7c0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spaced Text Type", "Text": "This type holds plain text and preserves all spacing. Other formatting of the text is not permitted. It could be useful to use the \"Tools > Customize Fonts\" command to set the editor font to a mono-spaced font when using this field type." }, "format": "HEAD_PARA", "uid": "f16ff8f6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Number Type", "Text": "In the number type, special characters in the format define the display of the numbers. The format uses a string of \"#\" (optional digit) and \"0\" (required digit) characters to define the output formatting. For example, pi formatted with \"#.#\" is \"3.1\" and formatted with \"00.00\" is \"03.14\". Regardless of the formatting, digits to the left of the decimal point are not truncated, since that would display an incorrect result. But use care to show enough decimal places (either optional or required) to avoid problems with round-off error.
\n
\nThe radix character can be specified as either \".\" or \",\" to handle internationalization. For use as a thousands separator, use \"\\,\" or \"\\.\". For example, a large number may be formatted as \"#\\,###\\,###.##\" or as \"#\\.###\\.###,##\". Press the \"Format Help\" button from the field format dialog for more formatting details.
\n
\nUnlike most other formats, the number type also uses the output format for display in the Data Editor. Of course, any new entry with a reasonable format is correctly interpreted (but the correct radix character must be used)." }, "format": "HEAD_PARA", "uid": "f16ff9faa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Boolean Type", "Text": "This type gives two choices corresponding to true/false values. The format help menu includes typical values such as \"yes/no\", \"true/false\" and \"1/0\", but users can also enter their own word pair. The data editor boxes will accept either the currently set format or any of the typical values." }, "format": "HEAD_PARA", "uid": "f16ffb08a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Date Type", "Text": "In the date field type, special characters in the format (all starting with \"%\") are replaced by elements of the data, similar to number fields. Press the \"Format Help\" button from the field format dialog for formatting details. Non-special characters will be output as themselves.
\n
\nThere is also an edit format under \"Tools > General Options > Data Editor Formats\". This controls how date fields are displayed in the Data Editor view. Generally, entries in the data editor with various formats will be correctly interpreted regardless of this setting, but dates must use the correct day-month-year sequence. Also note that the date editor format does not support days of the week.
\n
\nA default initial field value of \"Now\" can be used to enter the date of node creation." }, "format": "HEAD_PARA", "uid": "f16ffc02a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Time Type", "Text": "In the time field type, special characters in the format (all starting with \"%\") are replaced by elements of the data, similar to number fields. Press the \"Format Help\" button from the field format dialog for formatting details. Non-special characters will be output as themselves.
\n
\nThere is also an edit format under \"Tools > General Options > Data Editor Formats\". This controls how time fields are displayed in the Data Editor view. Generally, entries in the data editor with various formats will be correctly interpreted regardless of this setting.
\n
\nA default initial field value of \"Now\" can be used to enter the time of node creation." }, "format": "HEAD_PARA", "uid": "f16ffd06a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "DateTime Type", "Text": "The DateTime field combines dates and times into a single field that is useful for timestamps. Special characters in the format (all starting with \"%\") are replaced by elements of the data, as in date and time fields. Press the \"Format Help\" button from the field format dialog for formatting details. Non-special characters will be output as themselves.
\n
\nThe DateTime edit format is uses the date and time formats located in \"Tools > General Options > Data Editor Formats\". The date and time formats are combined, separated by a space character.
\n
\nA default initial field value of \"Now\" can be used to enter the date and time of node creation." }, "format": "HEAD_PARA", "uid": "f16ffe14a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Choice Type", "Text": "The choice field type allows for the selection of text items from a pull-down edit list. The formatting strings for these types list the items separated with the \"/\" character (use \"//\" to get a literal \"/\" in an item). Entries in the data editor which do not match the choices will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with \"#####\"." }, "format": "HEAD_PARA", "uid": "f16fff18a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Auto Choice Type", "Text": "This field type is similar to the choice type, but without a format string. The entries in the pull-down menu are automatically generated from all previously used entries. Any entries that are typed will be available in the pull-down menu for future use. " }, "format": "HEAD_PARA", "uid": "f1700008a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Combination Type", "Text": "This is basically the equivalent of the choice type with multiple selection. The formatting string entries are separated by the \"/\" character. The pull-down menu shows check-boxes that are checked for currently selected nodes. By default, the selected entries are output separated by a comma and a space. This can be changed in the \"Type Config\" tab of the \"Data > Configure Types Dialog\". Click the \"Show Advanced\" button to see the separator setting." }, "format": "HEAD_PARA", "uid": "f1700102a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Auto Combination Type", "Text": "This field type is similar to the combination type, but without a format string. The entries in the pull-down menu are automatically generated from all previously used entries. Any entries that are typed will be available in the pull-down menu for future use. " }, "format": "HEAD_PARA", "uid": "f1700206a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "External Link Type", "Text": "This type can support various link protocols, including http and https for web pages, mailto for email addresses and file for local files. A pull down dialog in the data editor allows the selection of the protocol type and the entry of an address and a display name. In the edit boxes, the display name shows up in [brackets], and it is used as the text of the link in the output view. The \"file\" protocol also provides a button to browse for a path and buttons to choose either absolute or relative path names.
\n
\nClicking on the link in the output view or choosing \"Open Link\" from the right-click context menu in the edit box will open the link in a web browser. In Linux, setting the \"BROWSER\" environment variable to a string like \"mozilla %s\" will result in the desired browser being used." }, "format": "HEAD_PARA", "uid": "f1700300a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Internal Link Type", "Text": "These links create shortcuts to select nodes elsewhere in the tree structure. To create a link, click the pull-down arrow and then select the target node in the tree view. The display name is shown in brackets. It is initially set to the target node title, but it can be edited. The right-click context menu can be used to clear the link or to select the target node.
\n
\nClicking the link in the output view will select the target node in the tree view." }, "format": "HEAD_PARA", "uid": "f1700404a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Picture Type", "Text": "These links add referenced pictures to the output view. A pull down dialog in the data editor has a button to browse for picture files to be linked. It also allows absolute or relative paths to be used and has a small image preview." }, "format": "HEAD_PARA", "uid": "f17004fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math Type", "Text": "Math field types are configured by defining equations. The equations can reference number fields, date fields, time fields, boolean fields, text fields and/or other math fields. The resulting values of math fields are automatically calculated for each node. Various mathematical, relational and string operators are available. The results can be numbers, text, boolean, dates or times.

To define a math field equation, press the \"Define Equation\" button in the \"Field Config\" tab of the \"Data > Configure Types Dialog\". This brings up a dialog with fields to reference on the left and math operators on the right. The \"Reference Level\" pull-down determines whether the reference is from the same node, the node's parent, the root node, or the node's children. The \"Result Type\" pull-down allows arithmetic, date, time, boolean or text results to be chosen. The \"Operator Type\" pull-down allows numeric, comparison or text operators to be shown in the operator list. The down-arrow buttons below the references and operators add the selected item to the equation text below. Portions of equations can also be typed directly in the equation text line editor.

References to child nodes must be enclosed in a grouping function, such as sum, max, min, mean or join. A math field can contain a parent or child reference to itself, but not a same-level reference to itself (a circular reference). The references only contain the field name, so they will reference a parent or child field with that name even if it is a different node type.

In equations, date fields are represented by the number of days since January 1, 1970, and time fields are the number of seconds since midnight. So date fields can be subtracted to give the number of days elapsed, and numbers of days can be added to or subtracted from dates to result in new dates. Time fields can be subtracted to give the number of seconds elapsed, and numbers of seconds can be added to or subtracted from times to result in new times. Also, special field names ({*Now_Date*}, {*Now_Time*} and {*Now_Date_Time*}) can be manually typed in equations to represent current dates and times. The \"Data->Regenerate References\" command may be needed to force re-evaluation of time-based references.

The \"if\" comparison operator can be used to make the result depend on the value of another field. The expression is written as \"true_value if condition else false_value\". Of course, the \"true_value\", \"condition\" and \"false_value\" strings must be replaced with valid fields or expressions. If this operator is inserted from the operator list (under comparisons), it will include parenthesis as placeholders. These parenthesis are optional in the equations.

The \"join\" text function is used to combine text from several other fields (or from child nodes). The first argument to the function is a separator string that is placed between each piece of text. The remaining argument(s) are the text to be joined.

By default, math fields are shown in the data edit view, but they are read-only. To hide them, uncheck the \"Show math fields in the Data Edit View\" box under \"Tools > General Options > Features Available\".

There is also an option under \"File > Properties\" that toggles whether blank fields are treated as zeros. If checked (the default), a blank field that is referenced by a math field has a value of zero (for numeric operations) or blank (for text operations). If unchecked, any blank references also cause equations that reference them to be blank.
" }, "format": "HEAD_PARA", "uid": "f17005f8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Numbering Type", "Text": "This type (not to be confused with the number type above) provides fields that are automatically filled in with the \"Data > Update Numbering\" command. The \"Format Help\" button in the field format dialog shows the output format options. A single format level will result in a simple sequential numbering scheme. Use of the \"/\" level separator will result in an outline-type numbering with different sequences at different levels. Use of the \".\" section separator will result in a \"2.3.5\" type numbering scheme.
\n
\nSince numbering fields are automatically populated, by default they are not shown in the data edit view. To show them, check the \"Show numbering fields in the Data Edit View\" box under \"Tools > General Options > Features Available\". When they are shown in the data edit view, they show up in section numbering style, regardless of the output format." }, "format": "HEAD_PARA", "uid": "f1700710a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Regular Expression Type", "Text": "This type allows arbitrary format strings to be matched that restrict the data to a particular format. It uses Python regular expression syntax. Entries in the data editor which do not match the format string expression will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with \"#####\"." }, "format": "HEAD_PARA", "uid": "f170081ea25a11e7b7c67054d2175f18" }, { "children": [ "f1700a26a25a11e7b7c67054d2175f18", "f1700b34a25a11e7b7c67054d2175f18", "f1700c38a25a11e7b7c67054d2175f18", "f1700d3ca25a11e7b7c67054d2175f18", "f1700e40a25a11e7b7c67054d2175f18", "bbbf735ac24711e8b560d66a6ab671cb" ], "data": { "Name": "Output Formatting Details" }, "format": "HEADINGS", "uid": "f1700936a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Output Format Examples", "Text": "Here is an example of output formatting for a book list:
\n
\n\"{*Title*}\"
\n(c) {*Copyright*}, Rating: {*Rating*}
\n{*PlotDescription*}
\n
\nEach of the field names in enclosed in {* *}, curly brackets and asterisks. For more examples, see the sample files that can be opened using the \"File > Open Sample\" command." }, "format": "HEAD_PARA", "uid": "f1700a26a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Title Formats", "Text": "When a node in the tree is renamed, the program attempts to match the title formatting pattern to set the appropriate fields (the same title matching occurs when editing lines in the \"Title List\" view). If the title formatting is too complex, it may not correctly guess the intent. Things like adjacent fields with no characters separating them should be avoided unless you do not wish to rename nodes from the tree.
\n
\nIf the text data used for a tree view title has multiple lines, only the first line will be used as the title." }, "format": "HEAD_PARA", "uid": "f1700b34a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Skipped Output Lines", "Text": "If all of the fields in an output format line are empty for a given node, then the line is skipped. No blank line or embedded text will be output for that line. Note that this does not apply to a line without any fields (only embedded text). Also, when a line ending with a <br/> or an <hr/> tag is skipped, the ending tag is retained." }, "format": "HEAD_PARA", "uid": "f1700c38a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML Tags", "Text": "By default, the \"Allow HTML rich text in formats\" option is unchecked in the \"Type Config\" tab of the Configure Types Dialog. So any HTML tags are treated as plain text. If the option is enabled, simple HTML formatting tags can be used in node output formats.
\n
\nCommonly used tags include \"<b>bold</b>\", \"<u>underline</u>\", \"line break<br/>\", \"horizontal line<hr/>\", and various font tags. Complex block tags should generally be avoided." }, "format": "HEAD_PARA", "uid": "f1700d3ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Other Field References", "Text": "References to fields that are not contained within the node can be added to the output. Pushing the \"Show Advanced\" button on the \"Output\" tab of the configure dialog makes a reference level selection become visible.
\n
\nIf the reference level is changed to \"File Info Reference\", fields containing file meta-data can be added to the output. These include the file name, path, size, modified date and modified time. These special fields are shown as \"{*!field_name*}\" in the title and output format editors.
\n
\nThere are field references to various ancestor nodes (parents, grandparents, etc.). These require the data type of the reference to be specified. This selection determines the field names that are available, but the data from any type with a matching field name will be shown in the output. References to fields from parent and grandparent nodes are shown as \"{**field_name*}\" and \"{***field_name*}\", respectively. There are also general ancestor references, shown as \"{*?field_name*}\", that take data from the closest ancestor with a matching field.
\n
\nReferences to child nodes can also be added, shown as \"{*&field_name*}\". These also require that the child data type be specified. The child data becomes embedded in the parent output. The child data is delimited with a separator string defined on the \"Type Config\" tab (with show advanced active). The separator defaults to a comma and a space, but can be set to <br/> or anything else.
\n
\nFinally, a \"Child Count\" reference can be added. This field will show the number of children (\"Level1\" field) or grandchildren (\"Level2\" field) of a node. These are shown as {*#Level1*} in the format editors.
\n
\nFor examples of these fields, see the \"sample_other_fields\" file (by using the \"File > Open Sample\" command)." }, "format": "HEAD_PARA", "uid": "f1700e40a25a11e7b7c67054d2175f18" }, { "children": [ "f1701156a25a11e7b7c67054d2175f18", "f170125aa25a11e7b7c67054d2175f18", "f1701368a25a11e7b7c67054d2175f18", "aa6f6ca4bb0711e7bbf43417ebd53aeb" ], "data": { "Name": "Type Format Details" }, "format": "HEADINGS", "uid": "f1700f58a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Generic and Derived Types", "Text": "Data types can be set to derive their field settings from a generic type. This allows types with different output formatting to always use the same set of fields. Any changes to the generic's list of fields and field types are automatically reflected in the fields of all derived types. This does not apply to a field's output formatting, which can still be set independently.
\n
\nThere are two methods for creating derived types. First, a derived option can be selected when copying a type on the \"Type List\" tab of the \"Data > Configure Types Dialog\". Alternately, a generic type can be specified from the derived type's \"Type Config\" tab of the dialog if the advanced functions are shown." }, "format": "HEAD_PARA", "uid": "f1701156a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional Types", "Text": "Conditional expressions can be used to automatically assign a data type based on each node's content. Conditions can be assigned only to a generic type and its associated derived types. This allows the automatic assignment of different output formatting or different icons depending on each node's field data.

The conditional dialog box is accessed from a button on the \"Type Config\" tab of the \"Data->Configure Types Dialog\" if the advanced functions are shown. Each line of the condition includes a field, an operator and a comparison value. The operators include equality, greater than, less than, starts with, ends with, and contains. There are also True and False operators that will toggle the type of all nodes simultaneously.

For special field types such as dates, times, and booleans, the comparison value should be entered in the same format that is used in the Data Editor window. In general, the starts with, ends with, and contains operators should not be used for these special fields, since the comparison is done using an internal data representation. Dates and times also support a special comparison value of \"Now\", which is always interpreted as the current date and time. The \"Data->Regenerate References\" command may be needed to force re-evaluation of time-based references.

The \"Add New Rule\" button is used to add additional condition lines. The lines can be joined with \"and\" or \"or\" operators. The \"Remove Rule\" button deletes the last condition line. If only a single line is present, the \"Remove Rule\" button completely removes the condition.

Conditions do not have to be set for all types in a family. If no conditions are true for a node, the program will select a blank condition rather than a false one.

For an example, see the \"sample_conditional_todo\" file (by using the \"File > Open Sample\" command)." }, "format": "HEAD_PARA", "uid": "f170125aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Copying Formats", "Text": "Another method for changing data type formatting is to copy the formats from another TreeLine file. This is done with the \"Data > Copy Types from File\" command. All types from the chosen file are copied. Any types in the current file with matching names are overwritten, but types with unique names are retained." }, "format": "HEAD_PARA", "uid": "f1701368a25a11e7b7c67054d2175f18" }, { "children": [ "f170155ca25a11e7b7c67054d2175f18", "f1701660a25a11e7b7c67054d2175f18", "f1701764a25a11e7b7c67054d2175f18", "f1701868a25a11e7b7c67054d2175f18", "f170198aa25a11e7b7c67054d2175f18", "f1701a8ea25a11e7b7c67054d2175f18" ], "data": { "Name": "Tree Data Operations" }, "format": "HEADINGS", "uid": "f170146ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sorting", "Text": "The \"Data > Sort Nodes\" command can sort nodes based on either node titles or key fields predefined in the node type configuration. The predefined sort fields can be changed in the \"Field Config\" tab of the Configure Types Dialog. The \"Sort Keys\" button brings up a list of fields that define a sort key sequence. The fields higher in the sequence have a higher priority. The direction for each key field can be flipped." }, "format": "HEAD_PARA", "uid": "f170155ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Numbering", "Text": "The \"Data > Update Numbering\" command updates the contents of fields with a special numbering field type. The field's output format defines how the numbers are displayed in the output, including whether individual numbers, outline numbers or a section numbering scheme are shown. See the Numbering Field Type for more information.
\n
\nNote that numbering fields are not shown in the data edit view unless \"Show numbering fields in the Data Edit View\" is checked under \"Tools > General Options > Features Available\". When they are shown in the data edit view, they show up in section numbering style, regardless of the output format." }, "format": "HEAD_PARA", "uid": "f1701660a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Find and Replace", "Text": "The \"Tools > Find and Replace\" command can be used to change the text in several nodes. The search text and replacement text are entered. Searching can be based on any match, full words only, or a Python regular expression. The operation can optionally be restricted to a particular node type and to a particular node field.
\n
\nReplacement using regular expressions is quite powerful. Searching for \".*\" will match all of the text in the field. The replacement string can contain back references that consist of a backslash and a number. The back references get replaced with the corresponding parenthesized group from the match. For example, \"\\2\" will be replaced with the text that matched the second group of parenthesis. The \"\\g<0>\" back-reference can be used to substitute the entire matching string." }, "format": "HEAD_PARA", "uid": "f1701764a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spell Check", "Text": "There is a spell check command in the \"Tools\" menu. Use of this command requires an external program to be installed (either aspell, ispell or hunspell- see the System Requirements section). If there are any misspelled words in the selected branch, a dialog will allow the word to be ignored, added to the dictionary, replaced with a suggestion or edited. This will spell check the text in all data fields of each node." }, "format": "HEAD_PARA", "uid": "f1701868a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Cloned Nodes", "Text": "Cloned nodes are used to duplicate sections of the tree. Editing their data or child structure in one location changes all locations. When a cloned node is selected, multiple lines are shown in the Breadcrumb view, showing ancestor nodes that have multiple parents. The selected node will appear black (not a link), but its clones can be clicked to select their location in the tree view.
\n
\nCloned nodes are created by copying nodes or branches and then using the special paste clone commands found in the \"Edit\" menu to paste them elsewhere. The clone link can be removed by deleting the nodes or by using the \"Data > Detach Clones\" command to convert them back to regular nodes.
\n
\nCloned nodes can also be created automatically by using the \"Data > Clone All Matched Nodes\" command. This will convert all identical nodes in the tree structure into cloned nodes.
\n
\nFor an example of cloned nodes with multiple parents, see the \"sample_genealogy\" file (by using the \"File > Open Sample\" command)." }, "format": "HEAD_PARA", "uid": "f170198aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Category-Based Arrangement", "Text": "The \"Data\" menu contains commands for arranging and flattening the data by category. These methods are used to automatically add and remove levels of nodes below the current node in the tree.
\n
\nThe \"Add Category Level\" command allows you to select one or more of the fields that the child nodes have in common. These fields are used to create new parent nodes for the children, grouping them by common categories. For example, in a list of books, picking the \"author_first_name\" and \"author_last_name\" fields will result in a tree with the books under new nodes for each unique author.
\n
\nThe \"Flatten by Category\" command is almost the opposite of \"Add Category Level\". It eliminates any descendant nodes with children, transferring their data fields to their children. It will rename fields instead of overwriting data with the same field names, but this command is most useful when the children and parents are different types with unique field names.
\n
\nThere is also a \"Swap Category Levels\" command that will swap the child and grandchild nodes beneath a selected node. A child node with multiple nodes under it will become cloned under each one. Any existing grandchild clones will become individual nodes with multiple children." }, "format": "HEAD_PARA", "uid": "f1701a8ea25a11e7b7c67054d2175f18" }, { "children": [ "f1701d90a25a11e7b7c67054d2175f18", "f1701e8aa25a11e7b7c67054d2175f18", "f1701f84a25a11e7b7c67054d2175f18" ], "data": { "Name": "Printing" }, "format": "HEADINGS", "uid": "f1701caaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Print Setup", "Text": "The dialog for print setup contains four tabs. The first, General Options, includes settings for what part of the tree to print, whether to include lines to child nodes and whether to allow page breaks between a parent an its first child node. It also has place to set the printer queue, to make pagination and print previews more accurate. The second tab, Page Setup, includes paper size, orientation, margins and columns. The third tab selects the font for printing. The last tab, Header/Footer, defines text and file data meta-fields for inclusion in headers and footers." }, "format": "HEAD_PARA", "uid": "f1701d90a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Print Preview", "Text": "The Print Preview window shows how the printout will look with current print settings. It can be dragged larger to show more detail, or the zoom settings can be changed. It also includes buttons for the Print Setup dialog and for printing." }, "format": "HEAD_PARA", "uid": "f1701e8aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Print to PDF", "Text": "This command prompts for a path and file name to export a PDF file. It uses the current printer settings." }, "format": "HEAD_PARA", "uid": "f1701f84a25a11e7b7c67054d2175f18" }, { "children": [ "f170216ea25a11e7b7c67054d2175f18", "f1702272a25a11e7b7c67054d2175f18", "f170236ca25a11e7b7c67054d2175f18", "f1702470a25a11e7b7c67054d2175f18" ], "data": { "Name": "File Handling" }, "format": "HEADINGS", "uid": "f170207ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File Compression", "Text": "A TreeLine file is in a JSON text format. There are options to compress the files (gzip format) to save storage space. Individual files can be set to compressed mode from either \"File > Properties\" or from the file type pull-down in the save-as dialog." }, "format": "HEAD_PARA", "uid": "f170216ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File Encryption", "Text": "There is a file encryption option to password protect TreeLine files. Individual files can be set to encrypted mode from either \"File > Properties\" or from the file type pull-down in the save-as dialog. The encryption uses an SHA hash function as a stream cipher - it should be fairly secure." }, "format": "HEAD_PARA", "uid": "f1702272a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Auto-Save", "Text": "An auto-save feature can store unsaved files with a \"~\" appended to the file name. The backup files are automatically removed when the file is saved or TreeLine exits cleanly. The auto-save time interval is set in the general options. Setting the interval to zero disables this feature." }, "format": "HEAD_PARA", "uid": "f170236ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved Tree States", "Text": "When opening a recently used file, TreeLine will restore the states of open and selected nodes. This information is stored in the user's TreeLine configuration files. If desired, this feature can be disabled with a general option." }, "format": "HEAD_PARA", "uid": "f1702470a25a11e7b7c67054d2175f18" }, { "children": [ "f170265aa25a11e7b7c67054d2175f18", "f170275ea25a11e7b7c67054d2175f18", "f1702b46a25a11e7b7c67054d2175f18", "95547c38b97411e7a42a3417ebd53aeb", "f1702858a25a11e7b7c67054d2175f18", "f1702952a25a11e7b7c67054d2175f18", "f1702a42a25a11e7b7c67054d2175f18" ], "data": { "Name": "File Import" }, "format": "HEADINGS", "uid": "f170256aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "General Information", "Text": "A TreeLine file is in a specific JSON text format. Other types of files can be imported using the \"File > Import\" command, which will show a dialog box where the type of import can be selected. Alternatively, using the \"File > Open\" command with a non-TreeLine file will also show this dialog." }, "format": "HEAD_PARA", "uid": "f170265aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Text Import", "Text": "Several different text formats can be selected for import. Tab indented text creates a node title from each line in the file, structured based on the number of tabs before each line.
\n
\nThe comma-delimited (CSV) and the tab delimited text tables use the first line as a header row to create field names, then each additional row becomes a node with field data taken from each column. The CSV import with level numbers creates a tree structure from level numbers in the first column that are incremented to show child relationships.
\n
\nThe plain text, one node per line import creates a flat tree of node titles.
\n
\nFinally, the plain text paragraph import creates long text nodes from text separated by blank lines." }, "format": "HEAD_PARA", "uid": "f170275ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Treepad Import", "Text": "Files from the Treepad shareware program can be imported. Only Treepad text nodes are supported." }, "format": "HEAD_PARA", "uid": "f1702858a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "XML Import", "Text": "TreeLine will import and export generic XML files. These routines do not have much intelligence - each XML element becomes a node and each XML attribute becomes a field. XML text content become fields named \"Element_Data\". This lets TreeLine function as a crude XML editor." }, "format": "HEAD_PARA", "uid": "f1702952a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "ODF Import", "Text": "TreeLine will import Open Document Format (ODF) text documents, from applications such as Apache OpenOffice and LibreOffice. The node structure is formed based on the heading styles assigned in the document. Any text under each heading is assigned to that heading's node. The import filter is intended for simple text outlines only. No formatting is maintained, and objects such as tables and pictures are not imported." }, "format": "HEAD_PARA", "uid": "f1702a42a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Bookmarks Import", "Text": "TreeLine will import bookmark files in both the Mozilla HTML format (Firefox browser) and the XBEL format (Konqueror, Galeon and Elinks browsers). Each bookmark becomes a node with a name and a link field. Some information in the files, such as visited dates and icon references, is not imported. For an example, see the \"sample_bookmarks\" file (by using the \"File > Open Sample\" command).
\n" }, "format": "HEAD_PARA", "uid": "f1702b46a25a11e7b7c67054d2175f18" }, { "children": [ "f1702d4ea25a11e7b7c67054d2175f18", "f1702e52a25a11e7b7c67054d2175f18", "f1702f60a25a11e7b7c67054d2175f18", "65289b36b97611e783eb3417ebd53aeb", "f1703064a25a11e7b7c67054d2175f18", "f170315ea25a11e7b7c67054d2175f18", "f1703262a25a11e7b7c67054d2175f18" ], "data": { "Name": "File Export" }, "format": "HEADINGS", "uid": "f1702c4aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "General Information", "Text": "Files are exported using the \"File > Export\" command. This will show a dialog box of available export types and options." }, "format": "HEAD_PARA", "uid": "f1702d4ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML Export", "Text": "The HTML export subtypes can export to a single page or to multiple pages. The single page export contains all of the indented output. A navigation pane on the left with links to anchors at node positions is optional.
\n
\nThe multiple HTML pages export has one web page per node. It includes a navigation pane on the left with links to the pages with sibling, parent and aunt/uncle nodes.
\n
\nMultiple HTML data tables export creates a table in each HTML file that contains the data for a set of siblings, as well as links to the parent and child pages.
\n
\nThe Live Tree HTML export uses Javascript and CSS to create an interactive view. Nodes in the tree can be expanded and collapsed, and a separate pane shows the output for all descendants of the selected node. The first form of this export creates separate files that are linked to the existing TreeLine file. These files are intended for use on a web server (browser security usually prevents local access). The HTML file stores the relative path from the TreeLine file to the initial export directory, so this relationship needs to be maintained on the web server. Only the TreeLine file needs to be replaced to update the data (re-export is not required).
\n
\nThe second form of Live Tree export creates a single file (with embedded data) that can be accessed from a local web browser. It appears the same as the first form on the browser." }, "format": "HEAD_PARA", "uid": "f1702e52a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Text Export", "Text": "Data can be exported to tabbed title text, comma-delimited (CSV) tables and tab-delimited tables. These formats are the same as the corresponding import formats.
\n
\nThere is also an unformatted text export the dumps all of the output into a text file without preserving the tree structure." }, "format": "HEAD_PARA", "uid": "f1702f60a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "XML Export", "Text": "TreeLine will import and export generic XML files. These routines do not have much intelligence - each node becomes an XML element and each field becomes an XML attribute, except for fields named \"Element_Data\" that become the element's text. This lets TreeLine function as a crude XML editor." }, "format": "HEAD_PARA", "uid": "f1703064a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "ODF Export", "Text": "TreeLine will export an outline to an Open Document Format (ODF) text document, compatible with Apache OpenOffice and LibreOffice. The title of each node is assigned a heading style at the appropriate level. Any other text in the output of each node becomes normal text under the heading. The export filter is intended for simple text outlines only. Any HTML formatting is stripped, and objects such as tables and pictures are not supported." }, "format": "HEAD_PARA", "uid": "f170315ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Bookmarks Export", "Text": "TreeLine will export bookmark files in both the Mozilla HTML format (Firefox browser) and the XBEL format (Konqueror, Galeon and Elinks browsers). TreeLine will look for a link field in each node that becomes the target of the bookmark." }, "format": "HEAD_PARA", "uid": "f1703262a25a11e7b7c67054d2175f18" }, { "children": [ "f1703442a25a11e7b7c67054d2175f18", "f1703546a25a11e7b7c67054d2175f18", "f170364aa25a11e7b7c67054d2175f18", "f1703744a25a11e7b7c67054d2175f18", "9ff09734dc9011ea887bac675dac20af", "f1703848a25a11e7b7c67054d2175f18", "7e9b3b88c24511e896c7d66a6ab671cb" ], "data": { "Name": "Customizations" }, "format": "HEADINGS", "uid": "f170335ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Options", "Text": "TreeLine's behavior can be modified with several settings available in \"Tools > General Options\". Most of these options are covered elsewhere in this document." }, "format": "HEAD_PARA", "uid": "f1703442a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Keyboard Shortcuts", "Text": "Keyboard shortcuts can be customized by using the \"Tools > Set Keyboard Shortcuts\" command. Simply type the new key sequence with the appropriate field selected." }, "format": "HEAD_PARA", "uid": "f1703546a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Toolbars", "Text": "An editor to customize the toolbars is available from \"Tools > Customize Toolbars\". The number of toolbars can be set, and the buttons on each can be defined." }, "format": "HEAD_PARA", "uid": "f170364aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Fonts", "Text": "The default font used in the application can be set using the \"Tools > Customize Fonts\" menu. There are also options to specify fonts used in the tree views, the output view and the editor views." }, "format": "HEAD_PARA", "uid": "f1703744a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Tree Icons", "Text": "There is an icons directory in the user configuration directory (\"~/.treeline-x.x/icons\" on Linux, \"Users\\<user>\\AppData\\roaming\\bellz\\treeline-x.x\\icons\" on Windows). Image files (PNG or BMP) placed into this directory are available for use as tree icons." }, "format": "HEAD_PARA", "uid": "f1703848a25a11e7b7c67054d2175f18" }, { "children": [ "65157f8a9b0c11f091375847ca7850fa", "414f6662813311f0b43b5847ca7850fa", "57d4ac00fe7f11edbb2654b2039ee1f3", "4f1366fa2ca811eda95c54b2039ee1f3", "b5fe698830e111ebbc097054d2175f18", "7ffeb66ddc8711ea9a87ac675dac20af", "194b0533e5d811e9b5fea44cc8e97404", "db25cd62481e11e989f27054d2175f18", "800a0971305111e991cda44cc8e97404", "9c08f39ee80311e8a510a44cc8e97404", "6610203fd2c111e8b033d66a6ab671cb", "67e95a5bbbf611e891f7a44cc8e97404", "e8e10d33a14311e88e24a44cc8e97404", "4bc47248786711e8a8bfa44cc8e97404", "95a6e90a333f11e89efed66a6ab671cb", "6df9a0c5ba3b11e78e7e3417ebd53aeb", "f1703e7ea25a11e7b7c67054d2175f18", "f1704752a25a11e7b7c67054d2175f18", "f170527ea25a11e7b7c67054d2175f18", "f170652aa25a11e7b7c67054d2175f18", "f1706be2a25a11e7b7c67054d2175f18", "f170748ea25a11e7b7c67054d2175f18", "f1708032a25a11e7b7c67054d2175f18", "f1708ae6a25a11e7b7c67054d2175f18", "f170ab34a25a11e7b7c67054d2175f18", "f170c1aaa25a11e7b7c67054d2175f18", "f170e900a25a11e7b7c67054d2175f18", "f170fddca25a11e7b7c67054d2175f18", "f1710e58a25a11e7b7c67054d2175f18", "f1711f24a25a11e7b7c67054d2175f18" ], "data": { "Name": "Revision History" }, "format": "HEADINGS", "uid": "f1703d8ea25a11e7b7c67054d2175f18" }, { "children": [ "f1703f8ca25a11e7b7c67054d2175f18", "f170427aa25a11e7b7c67054d2175f18" ], "data": { "Name": "March 26, 2017 - Release 2.1.2 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1703e7ea25a11e7b7c67054d2175f18" }, { "children": [ "f170407ca25a11e7b7c67054d2175f18", "f1704176a25a11e7b7c67054d2175f18" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "f1703f8ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It may contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) should probably be used for critical work." }, "format": "BULLETS", "uid": "f170407ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations have not yet been updated." }, "format": "BULLETS", "uid": "f1704176a25a11e7b7c67054d2175f18" }, { "children": [ "f1704360a25a11e7b7c67054d2175f18", "f170445aa25a11e7b7c67054d2175f18", "f1704554a25a11e7b7c67054d2175f18", "f170464ea25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170427aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "DateTime output", "Text": "Fix problems formatting DateTime fields in output views." }, "format": "BULLETS", "uid": "f1704360a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Internal links", "Text": "Fix dialog issues with clicking on targets when creating inline internal links." }, "format": "BULLETS", "uid": "f170445aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data view tabbing", "Text": "Fix a regression that prevented using the tab key to cycle between data edit view items." }, "format": "BULLETS", "uid": "f1704554a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Autosave restore", "Text": "Avoid opening two windows when restoring an auto-saved backup file." }, "format": "BULLETS", "uid": "f170464ea25a11e7b7c67054d2175f18" }, { "children": [ "f1704842a25a11e7b7c67054d2175f18", "f1704b30a25a11e7b7c67054d2175f18", "f1704d1aa25a11e7b7c67054d2175f18" ], "data": { "Name": "March 12, 2017 - Release 2.1.1 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1704752a25a11e7b7c67054d2175f18" }, { "children": [ "f1704928a25a11e7b7c67054d2175f18", "f1704a2ca25a11e7b7c67054d2175f18" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "f1704842a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It may contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) should probably be used for critical work." }, "format": "BULLETS", "uid": "f1704928a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations have not yet been updated." }, "format": "BULLETS", "uid": "f1704a2ca25a11e7b7c67054d2175f18" }, { "children": [ "f1704c20a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1704b30a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Windows binary", "Text": "The Windows binary is now built using Python 3.6 and PyQt 5.8." }, "format": "BULLETS", "uid": "f1704c20a25a11e7b7c67054d2175f18" }, { "children": [ "f1704f54a25a11e7b7c67054d2175f18", "f170506ca25a11e7b7c67054d2175f18", "f1705166a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1704d1aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Set icon crash", "Text": "Fix a crash when changing the icon on the Type Config page of the Configure Data Types dialog box." }, "format": "BULLETS", "uid": "f1704f54a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Type list issues", "Text": "Fix inconsistent type selections on the Type List page of the Configure Data Types dialog box." }, "format": "BULLETS", "uid": "f170506ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Window placement", "Text": "Fix issues with restoring the placement of the TreeLine window in some multiple monitor setups." }, "format": "BULLETS", "uid": "f1705166a25a11e7b7c67054d2175f18" }, { "children": [ "f170536ea25a11e7b7c67054d2175f18", "f170565ca25a11e7b7c67054d2175f18", "f170603ea25a11e7b7c67054d2175f18", "f1706228a25a11e7b7c67054d2175f18" ], "data": { "Name": "February 20, 2017 - Release 2.1.0 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170527ea25a11e7b7c67054d2175f18" }, { "children": [ "f170545ea25a11e7b7c67054d2175f18", "f1705558a25a11e7b7c67054d2175f18" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "f170536ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) should probably be used for critical work." }, "format": "BULLETS", "uid": "f170545ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations have not yet been updated." }, "format": "BULLETS", "uid": "f1705558a25a11e7b7c67054d2175f18" }, { "children": [ "f170574ca25a11e7b7c67054d2175f18", "f1705850a25a11e7b7c67054d2175f18", "f1705954a25a11e7b7c67054d2175f18", "f1705a4ea25a11e7b7c67054d2175f18", "f1705b48a25a11e7b7c67054d2175f18", "f1705c4ca25a11e7b7c67054d2175f18", "f1705d46a25a11e7b7c67054d2175f18", "f1705e40a25a11e7b7c67054d2175f18", "f1705f3aa25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170565ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Port to Qt5", "Text": "TreeLine has been ported from the Qt4 library to the Qt5 library. The system requirements have been updated to Python 3.4 or higher, PyQt 5.4 or higher and Qt 5.4 or higher." }, "format": "BULLETS", "uid": "f170574ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Cloned nodes", "Text": "Cloned nodes that can duplicate sections of the tree have been added. Editing their data or child structure in one location changes all locations. They are created by copying nodes and then using the \"Edit->Paste Cloned Node\" command to paste them elsewhere. The clone link can be removed by deleting the nodes or by cutting them and pasting them back using the regular paste command." }, "format": "BULLETS", "uid": "f1705850a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "DateTime field", "Text": "Added a new DateTime field that combines dates and times into a single field that is useful for timestamps. The editor format is a combination of the date and time formats from the general options, separated by a space." }, "format": "BULLETS", "uid": "f1705954a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML in choice fields", "Text": "Added an option to allow HTML tags in Choice, AutoChoice, Combination, AutoCombination and RegularExpression fields. The control is in the Field Config tab of the Configure Data Types dialog. This option is disabled by default. If enabled, special characters (angled brackets and quotation marks) will need to be escaped to show up in text." }, "format": "BULLETS", "uid": "f1705a4ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved conditional rules", "Text": "Saved rules for Conditional Find and Conditional Filter commands are listed directly in the dialog boxes, making them easier to load and save." }, "format": "BULLETS", "uid": "f1705b48a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "CSV import/export", "Text": "Added comma-delimited (CSV) table import and export, similar to existing tab-delimited table import and export. The export only handles data from a single level of child nodes." }, "format": "BULLETS", "uid": "f1705c4ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Incremental title search", "Text": "Added a quick, incremental search of node titles. By default, it's bound to ctrl+/. Then, matching titles are found as the search string is typed. The F3 and shift+F3 keys can be used to go to the next or previous matches, respectively." }, "format": "BULLETS", "uid": "f1705d46a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Multiple field selection", "Text": "Multiple fields can now be selected in the Output page of the Configuration dialog, so several fields can be added to the formats simultaneously." }, "format": "BULLETS", "uid": "f1705e40a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Print settings", "Text": "A pull-down selector for printers has been added to the Print Setup dialog. This enables TreeLine to verify that the page size and margin settings are supported by the current printer." }, "format": "BULLETS", "uid": "f1705f3aa25a11e7b7c67054d2175f18" }, { "children": [ "f170612ea25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170603ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "SpacedText Field special characters", "Text": "The SpacedText Field now allows special HTML characters (angled brackets and quotation marks) without requiring them to be manually escaped." }, "format": "BULLETS", "uid": "f170612ea25a11e7b7c67054d2175f18" }, { "children": [ "f170630ea25a11e7b7c67054d2175f18", "f1706426a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1706228a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Printed page splits", "Text": "The code that splits content into pages when printing has been improved. It now handles very long nodes better." }, "format": "BULLETS", "uid": "f170630ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Formatted field title edits", "Text": "When formatted fields (dates, times, etc.) are used in node titles, editing the titles in the tree or in the Title List pane will now work if the edit and output formats are similar." }, "format": "BULLETS", "uid": "f1706426a25a11e7b7c67054d2175f18" }, { "children": [ "f1706610a25a11e7b7c67054d2175f18", "f1706804a25a11e7b7c67054d2175f18" ], "data": { "Name": "October 3, 2015 - Release 2.0.2 (new stable release)" }, "format": "HEADINGS", "uid": "f170652aa25a11e7b7c67054d2175f18" }, { "children": [ "f1706700a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1706610a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data edit regression", "Text": "Fixed a major regression in 2.0.1 that broke data editors for most specialized field types (number, math, boolean, choice, etc.)" }, "format": "BULLETS", "uid": "f1706700a25a11e7b7c67054d2175f18" }, { "children": [ "f17068f4a25a11e7b7c67054d2175f18", "f17069e4a25a11e7b7c67054d2175f18", "f1706ae8a25a11e7b7c67054d2175f18" ], "data": { "Name": "Compatibility Notes" }, "format": "BULLET_HEADING", "uid": "f1706804a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File format", "Text": "There are some file format changes between TreeLine 1.4.x and this version of TreeLine." }, "format": "BULLETS", "uid": "f17068f4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File conversion", "Text": "Older files opened in this version are automatically converted when saved." }, "format": "BULLETS", "uid": "f17069e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File compatibility", "Text": "Files saved in this version may not be fully compatible with TreeLine 1.4.x." }, "format": "BULLETS", "uid": "f1706ae8a25a11e7b7c67054d2175f18" }, { "children": [ "f1706cd2a25a11e7b7c67054d2175f18", "f1706fb6a25a11e7b7c67054d2175f18" ], "data": { "Name": "September 26, 2015 - Release 2.0.1 (new stable release)" }, "format": "HEADINGS", "uid": "f1706be2a25a11e7b7c67054d2175f18" }, { "children": [ "f1706db8a25a11e7b7c67054d2175f18", "f1706ebca25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1706cd2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Plugin options", "Text": "Added methods to the plugin interface that allow general program options to be queried and changed." }, "format": "BULLETS", "uid": "f1706db8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Table import errors", "Text": "Improve text table import error messages by including the line number where the problem is found." }, "format": "BULLETS", "uid": "f1706ebca25a11e7b7c67054d2175f18" }, { "children": [ "f170709ca25a11e7b7c67054d2175f18", "f1707196a25a11e7b7c67054d2175f18", "f1707290a25a11e7b7c67054d2175f18", "f1707380a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1706fb6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data edit undo", "Text": "Reduce the amount of work that a single undo command removes from editors in the data edit view." }, "format": "BULLETS", "uid": "f170709ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Configuration changes", "Text": "Fixed a bug that prevented setting the unique ID reference field on a newly created data type." }, "format": "BULLETS", "uid": "f1707196a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Legacy newline convert", "Text": "Preserve hard newlines in text fields when converting TreeLine 1.4.x files to this version." }, "format": "BULLETS", "uid": "f1707290a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Indent expand status", "Text": "Fix problems preserving expand/collapse node states when indenting and unindenting nodes." }, "format": "BULLETS", "uid": "f1707380a25a11e7b7c67054d2175f18" }, { "children": [ "f1707592a25a11e7b7c67054d2175f18", "f1707c5ea25a11e7b7c67054d2175f18" ], "data": { "Name": "May 17, 2015 - Release 2.0.0 (new stable release)" }, "format": "HEADINGS", "uid": "f170748ea25a11e7b7c67054d2175f18" }, { "children": [ "f1707682a25a11e7b7c67054d2175f18", "f170777ca25a11e7b7c67054d2175f18", "f1707876a25a11e7b7c67054d2175f18", "f1707966a25a11e7b7c67054d2175f18", "f1707a60a25a11e7b7c67054d2175f18", "f1707b5aa25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1707592a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Treepad import update", "Text": "Modified the Treepad file import to use SpacedText fields to more closely match Treepad formatting." }, "format": "BULLETS", "uid": "f1707682a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Treepad export", "Text": "An optional plugin was written that can export files to the Treepad text file format." }, "format": "BULLETS", "uid": "f170777ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "New icon", "Text": "The TreeLine icon was replaced with a new one. Thanks to David Reimer for contributing the artwork." }, "format": "BULLETS", "uid": "f1707876a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translation updates", "Text": "The German and Portuguese GUI translations were updated." }, "format": "BULLETS", "uid": "f1707966a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sample file updates", "Text": "Updated the long text sample file to include the SpacedText field type, and added a conditional equation to the math sample file." }, "format": "BULLETS", "uid": "f1707a60a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Documentation update", "Text": "Updated the Math Field section of the documentation." }, "format": "BULLETS", "uid": "f1707b5aa25a11e7b7c67054d2175f18" }, { "children": [ "f1707d44a25a11e7b7c67054d2175f18", "f1707e3ea25a11e7b7c67054d2175f18", "f1707f38a25a11e7b7c67054d2175f18" ], "data": { "Name": "Compatibility Notes" }, "format": "BULLET_HEADING", "uid": "f1707c5ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File format", "Text": "There are some file format changes between TreeLine 1.4.x and this version of TreeLine." }, "format": "BULLETS", "uid": "f1707d44a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File conversion", "Text": "Older files opened in this version are automatically converted when saved." }, "format": "BULLETS", "uid": "f1707e3ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File compatibility", "Text": "Files saved in this version may not be fully compatible with TreeLine 1.4.x." }, "format": "BULLETS", "uid": "f1707f38a25a11e7b7c67054d2175f18" }, { "children": [ "f1708118a25a11e7b7c67054d2175f18", "f17083fca25a11e7b7c67054d2175f18", "f1708802a25a11e7b7c67054d2175f18" ], "data": { "Name": "March 29, 2015 - Release 1.9.7 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1708032a25a11e7b7c67054d2175f18" }, { "children": [ "f1708208a25a11e7b7c67054d2175f18", "f1708302a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f1708118a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field conditions", "Text": "Added comparison operators and conditional if statements to math field equations. The operators can be used with a new boolean result type, or as a part of numeric, date, time or text expressions." }, "format": "BULLETS", "uid": "f1708208a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field text operations", "Text": "Text operators were made available in math field equations, and the result type can be set to text. This allows math fields to combine text from other fields, replace sub-strings and change capitalization." }, "format": "BULLETS", "uid": "f1708302a25a11e7b7c67054d2175f18" }, { "children": [ "f17084eca25a11e7b7c67054d2175f18", "f17085f0a25a11e7b7c67054d2175f18", "f17086fea25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f17083fca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved status bar message", "Text": "Added a \"file saved\" status bar message." }, "format": "BULLETS", "uid": "f17084eca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "German translation", "Text": "Added a German GUI translation." }, "format": "BULLETS", "uid": "f17085f0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Portuguese translation", "Text": "Updated the Portuguese GUI translation." }, "format": "BULLETS", "uid": "f17086fea25a11e7b7c67054d2175f18" }, { "children": [ "f17088e8a25a11e7b7c67054d2175f18", "f17089e2a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1708802a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Combination editor", "Text": "Fixed a focus problem that made Combination and AutoCombination field editor pull-downs unusable." }, "format": "BULLETS", "uid": "f17088e8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Choice editor", "Text": "Fixed a focus problem that made the pull-downs in choice and boolean field editors unusable on Linux." }, "format": "BULLETS", "uid": "f17089e2a25a11e7b7c67054d2175f18" }, { "children": [ "f1708bcca25a11e7b7c67054d2175f18", "f17097aca25a11e7b7c67054d2175f18", "f170a2eca25a11e7b7c67054d2175f18" ], "data": { "Name": "March 10, 2015 - Release 1.9.6 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1708ae6a25a11e7b7c67054d2175f18" }, { "children": [ "f1708cbca25a11e7b7c67054d2175f18", "f1708db6a25a11e7b7c67054d2175f18", "f1708ea6a25a11e7b7c67054d2175f18", "f1708faaa25a11e7b7c67054d2175f18", "f17090aea25a11e7b7c67054d2175f18", "f17091e4a25a11e7b7c67054d2175f18", "f17092dea25a11e7b7c67054d2175f18", "f1709644a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f1708bcca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "OneLineText field", "Text": "Added a new OneLineText field type that restricts the text length to a single line." }, "format": "BULLETS", "uid": "f1708cbca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "All Types conditional test", "Text": "Added an All Types option to the conditional find and filter commands. This allows multiple node types to be found or filtered at the same time. The fields from every type are available for use in conditions. The conditions give a false result for all node types that do not contain that field name." }, "format": "BULLETS", "uid": "f1708db6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field dates and times", "Text": "Added support for date and time calculations using math fields. Math equation result types can be set to numeric, date or time output. Date fields can be subtracted to give the number of days elapsed, and numbers of days can be added to or subtracted from dates, resulting in new dates. Time fields can be subtracted to give the number of seconds elapsed, and numbers of seconds can be added to or subtracted from times, resulting in new times." }, "format": "BULLETS", "uid": "f1708ea6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field root references", "Text": "In math fields, added an equation reference level to reference fields in the root node. This provides a place for \"constant\" field values that can be referenced from any node but only need to be changed in one location." }, "format": "BULLETS", "uid": "f1708faaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Plugin interface", "Text": "Support was added for plugin extension modules. Most of the interface methods from TreeLine 1.4.x were duplicated to ease porting of old plugins. Of course, old plugins must be ported from Python 2.x to Python 3.x, and there are multi-window implementation differences. New interfaces allow the creation of new field types and the execution of any menu command. Sample plugins are available on the TreeLine download page." }, "format": "BULLETS", "uid": "f17090aea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Automatic HTML tags", "Text": "Added text formatting and link commands for HTML fields that add tags to the HTML content." }, "format": "BULLETS", "uid": "f17091e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Open in folder", "Text": "An open in folder command was added to external link field editors to open the directory in a file manager." }, "format": "BULLETS", "uid": "f17092dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Select All command", "Text": "Added the Select All command to global menus with a different default shortcut key (ctrl-L) to avoid conflicts with the add child shortcut." }, "format": "BULLETS", "uid": "f1709644a25a11e7b7c67054d2175f18" }, { "children": [ "f170989ca25a11e7b7c67054d2175f18", "f170998ca25a11e7b7c67054d2175f18", "f1709a7ca25a11e7b7c67054d2175f18", "f1709b8aa25a11e7b7c67054d2175f18", "f1709c7aa25a11e7b7c67054d2175f18", "f1709d6aa25a11e7b7c67054d2175f18", "f1709e50a25a11e7b7c67054d2175f18", "f1709f40a25a11e7b7c67054d2175f18", "f170a026a25a11e7b7c67054d2175f18", "f170a116a25a11e7b7c67054d2175f18", "f170a206a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f17097aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data edit view focus", "Text": "Improved the focus handling for data edit view edit boxes. This eliminates the blue outline for boxes in inactive data edit views. It also makes tab-to-focus more predictable, including fully selecting single-line field types when they receive tab focus." }, "format": "BULLETS", "uid": "f170989ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data editor resize", "Text": "Data edit boxes are now automatically resized when editing is complete and the focus moves to another row." }, "format": "BULLETS", "uid": "f170998ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drag external links", "Text": "Allow files to be drag & dropped on data edit boxes to create external links." }, "format": "BULLETS", "uid": "f1709a7ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Stay-on-top dialogs", "Text": "Small, non-modal dialogs, such as those for sorting, numbering, finding and filtering, have been set to stay on top, so they won't be obscured by TreeLine windows." }, "format": "BULLETS", "uid": "f1709b8aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Opening external links", "Text": "Made opening associated programs from external file links more consistent, especially in Linux." }, "format": "BULLETS", "uid": "f1709c7aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Copy types from file", "Text": "The copy types from file command now supports encrypted and compressed files." }, "format": "BULLETS", "uid": "f1709d6aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Wait cursors", "Text": "Added wait cursors to TreeLine operations that could be time consuming." }, "format": "BULLETS", "uid": "f1709e50a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Context menus", "Text": "Improved the consistency of context menus and shortcut commands used in edit boxes." }, "format": "BULLETS", "uid": "f1709f40a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Portuguese translation", "Text": "Added a nearly complete Portuguese GUI translation." }, "format": "BULLETS", "uid": "f170a026a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sample file languages", "Text": "Added support for sample TreeLine files to be provided in alternate languages." }, "format": "BULLETS", "uid": "f170a116a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Documentation translation", "Text": "Prepared the help file for translation into other languages," }, "format": "BULLETS", "uid": "f170a206a25a11e7b7c67054d2175f18" }, { "children": [ "f170a3d2a25a11e7b7c67054d2175f18", "f170a4b8a25a11e7b7c67054d2175f18", "f170a5a8a25a11e7b7c67054d2175f18", "f170a698a25a11e7b7c67054d2175f18", "f170a77ea25a11e7b7c67054d2175f18", "f170a86ea25a11e7b7c67054d2175f18", "f170a95ea25a11e7b7c67054d2175f18", "f170aa44a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170a2eca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Duplicate unique IDs", "Text": "Corrupted TreeLine files with the same unique ID assigned to multiple nodes no longer fail to open. The user is warned that unique IDs have been updated, which could break some internal links." }, "format": "BULLETS", "uid": "f170a3d2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional field list", "Text": "Fixed missing fields in the pull-down list in the conditional find and filter dialog boxes when a rule was re-used after a node type change. " }, "format": "BULLETS", "uid": "f170a4b8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field missing references", "Text": "Fixed problems with math fields that reference non-existing fields in parent or child nodes." }, "format": "BULLETS", "uid": "f170a5a8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field type updates", "Text": "Made math fields update properly after node type changes." }, "format": "BULLETS", "uid": "f170a698a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Rename bullet/table fields", "Text": "Fixed inconsistent updates after renaming fields used with bulleted or tabled output." }, "format": "BULLETS", "uid": "f170a77ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Copying descendants", "Text": "Made node copy-paste and drag-and-drop work when the initial selection includes both parent and child nodes. " }, "format": "BULLETS", "uid": "f170a86ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Tabbed text import", "Text": "When importing a tabbed text file with multiple top-level nodes, create a single higher-level node to prevent failure." }, "format": "BULLETS", "uid": "f170a95ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Custom toolbar dialog", "Text": "Fixed the availability of the move up button in the customize toolbar dialog when the second command in the list is selected." }, "format": "BULLETS", "uid": "f170aa44a25a11e7b7c67054d2175f18" }, { "children": [ "f170ac38a25a11e7b7c67054d2175f18", "f170afeea25a11e7b7c67054d2175f18", "f170b836a25a11e7b7c67054d2175f18" ], "data": { "Name": "December 31, 2014 - Release 1.9.5 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170ab34a25a11e7b7c67054d2175f18" }, { "children": [ "f170ad1ea25a11e7b7c67054d2175f18", "f170ae0ea25a11e7b7c67054d2175f18", "f170aefea25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170ac38a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field type", "Text": "Added a math field type that is configured by defining an equation. The field value is automatically calculated based on references to numerical values in other nodes. See the \"sample_math_fields\" file for a usage example." }, "format": "BULLETS", "uid": "f170ad1ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Clear formatting", "Text": "Added a Clear Formatting command that removes font changes and links from data editor text." }, "format": "BULLETS", "uid": "f170ae0ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "GUI Translations", "Text": "Made source code changes necessary to support user interface translations into other languages. The actual translation work remains to be done." }, "format": "BULLETS", "uid": "f170aefea25a11e7b7c67054d2175f18" }, { "children": [ "f170b0caa25a11e7b7c67054d2175f18", "f170b1baa25a11e7b7c67054d2175f18", "f170b2aaa25a11e7b7c67054d2175f18", "f170b390a25a11e7b7c67054d2175f18", "f170b480a25a11e7b7c67054d2175f18", "f170b570a25a11e7b7c67054d2175f18", "f170b656a25a11e7b7c67054d2175f18", "f170b746a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170afeea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Combination field scroll bars", "Text": "Add scroll bars to the pull-down editors for combination fields with many entries." }, "format": "BULLETS", "uid": "f170b0caa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "External link truncation", "Text": "Reduce the truncation of external link URLs when generating default display names." }, "format": "BULLETS", "uid": "f170b1baa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File newlines", "Text": "Use Unix-style newlines for saved TreeLine files to keep files consistent across platforms." }, "format": "BULLETS", "uid": "f170b2aaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML panes", "Text": "Update the CSS code in exported HTML with navigation panes to improve the appearance in some browsers." }, "format": "BULLETS", "uid": "f170b390a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Undo optimization", "Text": "Optimize some undo information to reduce the amount of data in memory." }, "format": "BULLETS", "uid": "f170b480a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Move sample files", "Text": "Move sample files into a separate directory to avoid future translation conflicts." }, "format": "BULLETS", "uid": "f170b570a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Installer clarification", "Text": "Clarify a Linux installer error message when checking for the Python 3 version of PyQt." }, "format": "BULLETS", "uid": "f170b656a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Include MSVC files", "Text": "Include MSVCR DLL files in the Windows installer." }, "format": "BULLETS", "uid": "f170b746a25a11e7b7c67054d2175f18" }, { "children": [ "f170b91ca25a11e7b7c67054d2175f18", "f170ba0ca25a11e7b7c67054d2175f18", "f170baf2a25a11e7b7c67054d2175f18", "f170bbeca25a11e7b7c67054d2175f18", "f170bcf0a25a11e7b7c67054d2175f18", "f170bde0a25a11e7b7c67054d2175f18", "f170bed0a25a11e7b7c67054d2175f18", "f170bfc0a25a11e7b7c67054d2175f18", "f170c0a6a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170b836a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Applying config dialog settings", "Text": "Fix problems applying multiple configuration changes while the Configure Data Types dialog box remains open." }, "format": "BULLETS", "uid": "f170b91ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Title list line split", "Text": "In the Title List editor, splitting a title into two lines now creates a new node without losing the children and parameters of the original node." }, "format": "BULLETS", "uid": "f170ba0ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Title list undo", "Text": "Fix the undo command in the Title List View so that deleted lines/nodes are properly restored. " }, "format": "BULLETS", "uid": "f170baf2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sorting by fields", "Text": "When sorting nodes by fields, properly handle a reverse direction." }, "format": "BULLETS", "uid": "f170bbeca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Find and replace", "Text": "Fix problems with the find and replace command when a particular node type is specified." }, "format": "BULLETS", "uid": "f170bcf0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional types", "Text": "Fix problems defining conditional types from the Configure Data Types dialog box." }, "format": "BULLETS", "uid": "f170bde0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Apply font sizes", "Text": "Correctly apply font size formatting to selections with mixed font sizes." }, "format": "BULLETS", "uid": "f170bed0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Editor height", "Text": "Fix the height of long text field editors with customized data editor fonts." }, "format": "BULLETS", "uid": "f170bfc0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Base 64 image export", "Text": "Fix HTML export of Base 64 images." }, "format": "BULLETS", "uid": "f170c0a6a25a11e7b7c67054d2175f18" }, { "children": [ "f170c286a25a11e7b7c67054d2175f18", "f170e068a25a11e7b7c67054d2175f18", "f170e46ea25a11e7b7c67054d2175f18" ], "data": { "Name": "March 8, 2014 - Release 1.9.4 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170c1aaa25a11e7b7c67054d2175f18" }, { "children": [ "f170d8d4a25a11e7b7c67054d2175f18", "f170d9d8a25a11e7b7c67054d2175f18", "f170dac8a25a11e7b7c67054d2175f18", "f170dbb8a25a11e7b7c67054d2175f18", "f170dca8a25a11e7b7c67054d2175f18", "f170dd98a25a11e7b7c67054d2175f18", "f170de88a25a11e7b7c67054d2175f18", "f170df6ea25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170c286a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Documentation", "Text": "Created new documentation, including a TreeLine file with details and a text file with basic usage instructions. Both are accessible from the help menu." }, "format": "BULLETS", "uid": "f170d8d4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Font settings", "Text": "Added customizing of default fonts used in the tree, output and editor views." }, "format": "BULLETS", "uid": "f170d9d8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spaced text field", "Text": "Added a new SpacedText field type that holds plain text and preserves all spacing." }, "format": "BULLETS", "uid": "f170dac8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Combination editor", "Text": "Combination and auto combination field types now use a simpler checkbox style pull-down editor." }, "format": "BULLETS", "uid": "f170dbb8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Autosave option", "Text": "An autosave option was added." }, "format": "BULLETS", "uid": "f170dca8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unique ID output", "Text": "A unique ID reference field was added to the file info fields to allow node unique IDs to be included in output formats." }, "format": "BULLETS", "uid": "f170dd98a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Paste plain text", "Text": "A plain text paste command was added to paste non-formatted text to data editors." }, "format": "BULLETS", "uid": "f170de88a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Indent option", "Text": "Added an option to set the child indent offset amount." }, "format": "BULLETS", "uid": "f170df6ea25a11e7b7c67054d2175f18" }, { "children": [ "f170e162a25a11e7b7c67054d2175f18", "f170e252a25a11e7b7c67054d2175f18", "f170e36aa25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170e068a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Print preview size", "Text": "The last size and position of the print preview window are remembered and restored." }, "format": "BULLETS", "uid": "f170e162a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Page breaks in nodes", "Text": "When printing, nodes with long text content are split between pages." }, "format": "BULLETS", "uid": "f170e252a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Export relative links", "Text": "In multiple page HTML exports, relative links in the content are adjusted based on the directory depth." }, "format": "BULLETS", "uid": "f170e36aa25a11e7b7c67054d2175f18" }, { "children": [ "f170e54aa25a11e7b7c67054d2175f18", "f170e63aa25a11e7b7c67054d2175f18", "f170e720a25a11e7b7c67054d2175f18", "f170e810a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170e46ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Blank nodes", "Text": "Fixed problems outputting completely blank nodes." }, "format": "BULLETS", "uid": "f170e54aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional rules", "Text": "Problems with the contains and true/false conditional rules were fixed." }, "format": "BULLETS", "uid": "f170e63aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Link dialogs", "Text": "Fixed issues displaying several editor link dialogs in quick succession." }, "format": "BULLETS", "uid": "f170e720a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Output config cursor", "Text": "In the configure data types dialog, the output format cursor no longer moves when switching to other field references." }, "format": "BULLETS", "uid": "f170e810a25a11e7b7c67054d2175f18" }, { "children": [ "f170e9dca25a11e7b7c67054d2175f18", "f170f12aa25a11e7b7c67054d2175f18", "f170f846a25a11e7b7c67054d2175f18" ], "data": { "Name": "January 19, 2014 - Release 1.9.3 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170e900a25a11e7b7c67054d2175f18" }, { "children": [ "f170eac2a25a11e7b7c67054d2175f18", "f170eba8a25a11e7b7c67054d2175f18", "f170ec8ea25a11e7b7c67054d2175f18", "f170ed74a25a11e7b7c67054d2175f18", "f170ee5aa25a11e7b7c67054d2175f18", "f170ef4aa25a11e7b7c67054d2175f18", "f170f030a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170e9dca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Keyboard shortcuts", "Text": "Added controls in the Tools menu for customizing TreeLine's keyboard shortcuts." }, "format": "BULLETS", "uid": "f170eac2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Toolbars", "Text": "Controls for customizing TreeLine's toolbar buttons were added to the Tools menu." }, "format": "BULLETS", "uid": "f170eba8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional search", "Text": "New dialogs were created for conditional finding and filtering of nodes. Specific conditions can be applied to individual types and fields, and the conditions can be saved." }, "format": "BULLETS", "uid": "f170ec8ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Find and replace", "Text": "Find and replace functionality was added to search and change nodes' text data. The search can be limited to specific types and fields." }, "format": "BULLETS", "uid": "f170ed74a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Table output", "Text": "A new option for output data in tables was added to the Type Config pane of the Configure Data Types dialog. Each line of the output format becomes a column. Any text at the start of the format line that is followed by a colon becomes a table heading." }, "format": "BULLETS", "uid": "f170ee5aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Bullet output", "Text": "An option to add bullets to the output of child nodes was added to the Type Config pane of the Configure Data Types dialog." }, "format": "BULLETS", "uid": "f170ef4aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Toggle selections", "Text": "Added View > Previous Selection and Next Selection commands to step through the node selection history." }, "format": "BULLETS", "uid": "f170f030a25a11e7b7c67054d2175f18" }, { "children": [ "f170f210a25a11e7b7c67054d2175f18", "f170f2f6a25a11e7b7c67054d2175f18", "f170f418a25a11e7b7c67054d2175f18", "f170f4fea25a11e7b7c67054d2175f18", "f170f5e4a25a11e7b7c67054d2175f18", "f170f6d4a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170f12aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drop to reorder", "Text": "Nodes can now be reordered by dragging and dropping them between sibling nodes." }, "format": "BULLETS", "uid": "f170f210a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Date entry formats", "Text": "The keyboard entry of dates and times into fields was made more flexible by allowing entries such as 4-digit years that don't exactly match the entry format." }, "format": "BULLETS", "uid": "f170f2f6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Default link names", "Text": "Any text selection is now used as the default name for links inserted into text fields." }, "format": "BULLETS", "uid": "f170f418a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Anchor links", "Text": "Links to local named anchors in a node's HTML text content now work if they don't conflict with any node unique IDs." }, "format": "BULLETS", "uid": "f170f4fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Line spacing", "Text": "Line spacing in output views was made more consistent." }, "format": "BULLETS", "uid": "f170f5e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved states", "Text": "Improved the efficiency of restoring node open/close states when opening files." }, "format": "BULLETS", "uid": "f170f6d4a25a11e7b7c67054d2175f18" }, { "children": [ "f170f936a25a11e7b7c67054d2175f18", "f170fa1ca25a11e7b7c67054d2175f18", "f170fb0ca25a11e7b7c67054d2175f18", "f170fbf2a25a11e7b7c67054d2175f18", "f170fce2a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170f846a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Paste font sizes", "Text": "Errors when pasting text with varying font sizes into data editors were fixed." }, "format": "BULLETS", "uid": "f170f936a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional data types", "Text": "Various issues with conditional data types were fixed, including problems with pasting conditional nodes and prompt updating when the types change." }, "format": "BULLETS", "uid": "f170fa1ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drag undo", "Text": "Problems with undoing the dragging and dropping of a node were fixed." }, "format": "BULLETS", "uid": "f170fb0ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Expand branches", "Text": "Fix the extremely slow operation of the View > Expand Full Branch and Collapse Full Branch commands." }, "format": "BULLETS", "uid": "f170fbf2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Printed lines", "Text": "Fix improperly placed branch lines in printed output." }, "format": "BULLETS", "uid": "f170fce2a25a11e7b7c67054d2175f18" }, { "children": [ "f170fec2a25a11e7b7c67054d2175f18", "f171053ea25a11e7b7c67054d2175f18", "f17108e0a25a11e7b7c67054d2175f18" ], "data": { "Name": "October 22, 2013 - Release 1.9.2 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170fddca25a11e7b7c67054d2175f18" }, { "children": [ "f170ffa8a25a11e7b7c67054d2175f18", "f171008ea25a11e7b7c67054d2175f18", "f171017ea25a11e7b7c67054d2175f18", "f1710264a25a11e7b7c67054d2175f18", "f171034aa25a11e7b7c67054d2175f18", "f1710430a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170fec2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spell check", "Text": "Added a spell check tool. This requires either aspell, ispell or hunspell to be installed." }, "format": "BULLETS", "uid": "f170ffa8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Numbering field type", "Text": "Included a node numbering field type with several formatting options. An update numbering command fills in the sequence." }, "format": "BULLETS", "uid": "f171008ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Add category level", "Text": "Added a command to add a category level based on a subset of data fields." }, "format": "BULLETS", "uid": "f171017ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Flatten by category", "Text": "Added a flatten by category command to combine parent fields into child nodes." }, "format": "BULLETS", "uid": "f1710264a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Flatten by link", "Text": "A new flatten by link command flattens the structure and provides internal links to the former parent nodes." }, "format": "BULLETS", "uid": "f171034aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Arrange by link", "Text": "An arrange by link command restores the structure based on parent internal links." }, "format": "BULLETS", "uid": "f1710430a25a11e7b7c67054d2175f18" }, { "children": [ "f171061aa25a11e7b7c67054d2175f18", "f171070aa25a11e7b7c67054d2175f18", "f17107f0a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f171053ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "URL drag-and-drop", "Text": "Allow file URL drag-and-drop on active external link data edit widgets." }, "format": "BULLETS", "uid": "f171061aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Share directory", "Text": "Change the Linux installer to use the 'share' directory in place of 'lib' for python files." }, "format": "BULLETS", "uid": "f171070aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Windows binary", "Text": "Update the Windows binary to use version 3.3 of Python." }, "format": "BULLETS", "uid": "f17107f0a25a11e7b7c67054d2175f18" }, { "children": [ "f17109bca25a11e7b7c67054d2175f18", "f1710aa2a25a11e7b7c67054d2175f18", "f1710b88a25a11e7b7c67054d2175f18", "f1710c78a25a11e7b7c67054d2175f18", "f1710d68a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f17108e0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Output line sequence", "Text": "Fix out of sequence output lines when output formats are longer than ten lines." }, "format": "BULLETS", "uid": "f17109bca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Node indenting", "Text": "Fix problems with unique IDs and internal links when indenting and unindenting nodes." }, "format": "BULLETS", "uid": "f1710aa2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Widget focus problems", "Text": "Avoid widget focus problems when editing data on conditional types." }, "format": "BULLETS", "uid": "f1710b88a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Format cursor position", "Text": "Maintain the output format cursor position when changing fields in the configure dialog." }, "format": "BULLETS", "uid": "f1710c78a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "XML import", "Text": "Fix importing of generic XML documents that have nodes with no data." }, "format": "BULLETS", "uid": "f1710d68a25a11e7b7c67054d2175f18" }, { "children": [ "f1710f48a25a11e7b7c67054d2175f18", "f17118a8a25a11e7b7c67054d2175f18" ], "data": { "Name": "May 2, 2013 - Release 1.9.1 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1710e58a25a11e7b7c67054d2175f18" }, { "children": [ "f171102ea25a11e7b7c67054d2175f18", "f171111ea25a11e7b7c67054d2175f18", "f171120ea25a11e7b7c67054d2175f18", "f17112fea25a11e7b7c67054d2175f18", "f17113eea25a11e7b7c67054d2175f18", "f17114dea25a11e7b7c67054d2175f18", "f17115d8a25a11e7b7c67054d2175f18", "f17116c8a25a11e7b7c67054d2175f18", "f17117b8a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1710f48a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Compression and encryption", "Text": "Added TreeLine file compression and file encryption, controlled from a File > Properties dialog box." }, "format": "BULLETS", "uid": "f171102ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Restore tree states", "Text": "Tree node open/close states are restored for recent files." }, "format": "BULLETS", "uid": "f171111ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Derived data types", "Text": "Added derived data types that keep the field list of their generic type." }, "format": "BULLETS", "uid": "f171120ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional type setting", "Text": "Added conditional type setting that changes icons or output format based on field contents." }, "format": "BULLETS", "uid": "f17112fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Other field references", "Text": "Other field references (file info, ancestors, children) can be used in node output formats and in print headers & footers." }, "format": "BULLETS", "uid": "f17113eea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML file export", "Text": "Added an HTML file export to a single file with a navigation pane on the side." }, "format": "BULLETS", "uid": "f17114dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Embedded blank lines", "Text": "Allow embedded blank lines in non-HTML node output formats." }, "format": "BULLETS", "uid": "f17115d8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Separator config option", "Text": "Added an output separator config option for combination fields and child references." }, "format": "BULLETS", "uid": "f17116c8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "First day of week option", "Text": "Add an option to set the first day of the week for calendar widgets." }, "format": "BULLETS", "uid": "f17117b8a25a11e7b7c67054d2175f18" }, { "children": [ "f1711998a25a11e7b7c67054d2175f18", "f1711a88a25a11e7b7c67054d2175f18", "f1711b6ea25a11e7b7c67054d2175f18", "f1711c54a25a11e7b7c67054d2175f18", "f1711d44a25a11e7b7c67054d2175f18", "f1711e2aa25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f17118a8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drag multiple nodes", "Text": "Fixed problems with pasting or dragging multiple nodes." }, "format": "BULLETS", "uid": "f1711998a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Remove fields from multi-line output formats", "Text": "Made removing fields from multi-line output formats work properly." }, "format": "BULLETS", "uid": "f1711a88a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Prevent duplicate unique IDs", "Text": "Prevent duplicate unique IDs from being created after undoing the deletion of a branch." }, "format": "BULLETS", "uid": "f1711b6ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Fixed non-text nodes sorting", "Text": "Fixed node sorting of non-text nodes (numbers, dates, times, etc.)" }, "format": "BULLETS", "uid": "f1711c54a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Calendar widgets", "Text": "Avoid placing calendar widgets partially off screen if near the bottom." }, "format": "BULLETS", "uid": "f1711d44a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Automatic cell height", "Text": "Limit the automatic height increases for text edit cells to avoid confusing double scroll bars." }, "format": "BULLETS", "uid": "f1711e2aa25a11e7b7c67054d2175f18" }, { "children": [ "f171200aa25a11e7b7c67054d2175f18" ], "data": { "Name": "February 6, 2013 - Release 1.9.0 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1711f24a25a11e7b7c67054d2175f18" }, { "children": [ "f17120e6a25a11e7b7c67054d2175f18", "f17121d6a25a11e7b7c67054d2175f18", "f17122c6a25a11e7b7c67054d2175f18", "f17123aca25a11e7b7c67054d2175f18", "f171249ca25a11e7b7c67054d2175f18", "f171258ca25a11e7b7c67054d2175f18", "f1712690a25a11e7b7c67054d2175f18", "f1712776a25a11e7b7c67054d2175f18", "f1712866a25a11e7b7c67054d2175f18", "f1712960a25a11e7b7c67054d2175f18", "f1712a46a25a11e7b7c67054d2175f18", "f1712b36a25a11e7b7c67054d2175f18", "f1712c1ca25a11e7b7c67054d2175f18", "f1712d02a25a11e7b7c67054d2175f18", "f1712df2a25a11e7b7c67054d2175f18", "f1712ed8a25a11e7b7c67054d2175f18", "f1712fbea25a11e7b7c67054d2175f18", "f1713194a25a11e7b7c67054d2175f18", "f1713284a25a11e7b7c67054d2175f18", "f171336aa25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f171200aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Full Python 3 rewrite", "Text": "TreeLine has been fully rewritten using Python 3." }, "format": "BULLETS", "uid": "f17120e6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Direct model-view and ElementTree", "Text": "Improved performance due to direct use of model-view classes for views and ElementTree for input/output." }, "format": "BULLETS", "uid": "f17121d6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Table based data editor pane", "Text": "A table based data editor pane (much faster)." }, "format": "BULLETS", "uid": "f17122c6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "WYSIWYG data editor view.", "Text": "WYSIWYG formatting in the data editor view." }, "format": "BULLETS", "uid": "f17123aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Real-time window updates ", "Text": "Real-time updates of the same file shown in multiple windows." }, "format": "BULLETS", "uid": "f171249ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Improved printing", "Text": "Improved printing and print preview performance." }, "format": "BULLETS", "uid": "f171258ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saves print options", "Text": "Saves print options with the TreeLine file." }, "format": "BULLETS", "uid": "f1712690a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Built-in PDF", "Text": "Built-in print to PDF function." }, "format": "BULLETS", "uid": "f1712776a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Searching options.", "Text": "More searching options." }, "format": "BULLETS", "uid": "f1712866a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Filtering command", "Text": "A filtering command shows matches in a simple list." }, "format": "BULLETS", "uid": "f1712960a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved sorting parameters", "Text": "Sorting parameters can be saved with each data type." }, "format": "BULLETS", "uid": "f1712a46a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Basic text field type", "Text": "The basic text field type allows formatting, preserves line breaks and allows HTML restricted characters." }, "format": "BULLETS", "uid": "f1712b36a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Calendar widget", "Text": "A calendar widget can be used for editing date fields." }, "format": "BULLETS", "uid": "f1712c1ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Easy internal links", "Text": "Internal link fields and inline internal links are easier to use." }, "format": "BULLETS", "uid": "f1712d02a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unified external links", "Text": "An external link type supports http, https, file and mailto protocols." }, "format": "BULLETS", "uid": "f1712df2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Support relative paths", "Text": "Relative paths are supported for external links and pictures." }, "format": "BULLETS", "uid": "f1712ed8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Regular expression field type", "Text": "A regular expression field type can match patterns (phone numbers, email addresses, etc.)" }, "format": "BULLETS", "uid": "f1712fbea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Node IDs automatically generated", "Text": "Unique node IDs are automatically generated and updated." }, "format": "BULLETS", "uid": "f1713194a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "New windows installer", "Text": "A new windows installer allows a single-user, non-administrator install." }, "format": "BULLETS", "uid": "f1713284a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Portable installs", "Text": "Includes better support for portable installs." }, "format": "BULLETS", "uid": "f171336aa25a11e7b7c67054d2175f18" }, { "children": [ "f171354aa25a11e7b7c67054d2175f18", "f1713644a25a11e7b7c67054d2175f18", "f171372aa25a11e7b7c67054d2175f18" ], "data": { "Name": "Contacts" }, "format": "HEADINGS", "uid": "f1713464a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Mailing list", "Text": "There is a low-volume mailing list for users to discuss anything and everything about TreeLine. This is the place for development discussions (from roadmaps to feature suggestions to beta testing), release announcements, bug reports, and general user discussions (from new uses to tips & tricks to configuration samples).
\n
\nTo subscribe, go to lists.sourceforge.net/lists/listinfo/treeline-users
\n" }, "format": "HEAD_PARA", "uid": "f171354aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Email", "Text": "If you do not wish to subscribe to the mailing list, I can be contacted by email at: doug101 AT bellz DOT org " }, "format": "HEAD_PARA", "uid": "f1713644a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Updates", "Text": "I welcome any feedback, including reports of any bugs you find. Also, you can periodically check back to treeline.bellz.org for any updates." }, "format": "HEAD_PARA", "uid": "f171372aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Network drive issues", "Text": "Work around bugs when using files located on some types of Windows network drives." }, "format": "BULLETS", "uid": "f2a0c0a1dc8d11ea8921ac675dac20af" }, { "children": [], "data": { "Name": "Error handling", "Text": "Error handling has been improved. For most errors, a dialog box is shown with debugging information that can be copied into an email." }, "format": "BULLETS", "uid": "f5983b38bb0411e795e13417ebd53aeb" }, { "children": [ "42fb4166305a11e99fd7a44cc8e97404", "014e1392305b11e9ab99a44cc8e97404", "46f3d0a4305e11e9892fa44cc8e97404", "f7bbd90a305111e98209a44cc8e97404", "221ca8f0305911e99f3fa44cc8e97404", "2c9ba0c832ed11e9bf7f7054d2175f18", "2d4430dc305711e9a33aa44cc8e97404", "1b73aaf4305811e98bb7a44cc8e97404" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f7bbd909305111e9be43a44cc8e97404" }, { "children": [], "data": { "Name": "Regenerate references command", "Text": "A new Regenerate References command was added to the Data menu. It forces updates to all conditional types and math fields. It should only be necessary for comparisons to current dates/times or for externally modified data." }, "format": "BULLETS", "uid": "f7bbd90a305111e98209a44cc8e97404" }, { "children": [], "data": { "Name": "XML export", "Text": "Fixed problems with generic XML export from multiple root nodes." }, "format": "BULLETS", "uid": "f817e5b6334a11e89349d66a6ab671cb" }, { "children": [], "data": { "Name": "Number formatting", "Text": "Removed deprecated string escapes used when formatting numbers." }, "format": "BULLETS", "uid": "f8ed5904813411f0b43b5847ca7850fa" }, { "children": [], "data": { "Name": "Spanish translation", "Text": "Added a Spanish GUI translation (thanks to Diego)." }, "format": "BULLETS", "uid": "f966db0cc23f11e8b80fd66a6ab671cb" }, { "children": [], "data": { "Name": "Printing empty branches", "Text": "Fix an error caused by attempting to print an empty branch." }, "format": "BULLETS", "uid": "fcc1b718e5df11e9a7f9a44cc8e97404" }, { "children": [ "6a6067d4482011e989f27054d2175f18", "b398d8ee482211e989f27054d2175f18", "ff3f7da6481e11e989f27054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "ff3f7c98481e11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "Updated German and Spanish GUI translations (thanks to Maria Seliger and Diego)." }, "format": "BULLETS", "uid": "ff3f7da6481e11e989f27054d2175f18" } ], "properties": { "tlversion": "3.2.1", "topnodes": [ "f16f7d90a25a11e7b7c67054d2175f18" ] } }TreeLine-3.2.1/doc/documentation_ru.trln000066400000000000000000020110411506556630100202570ustar00rootroot00000000000000{ "formats": [ { "bullets": true, "fields": [ { "fieldname": "Name", "fieldtype": "HtmlText", "sortkeynum": 1 }, { "fieldname": "Name_src", "fieldtype": "Text", "sortkeynum": 2 }, { "fieldname": "Text", "fieldtype": "HtmlText", "lines": 2 }, { "fieldname": "Text_src", "fieldtype": "HtmlText", "lines": 2 }, { "fieldname": "number", "fieldtype": "DateTime", "format": "%B %-d, %Y %-I:%M:%S %p" } ], "formathtml": true, "formatname": "BULLETS", "icon": "bullet_1", "outputlines": [ "{*Text*}{*intlink*}" ], "spacebetween": false, "titleline": "{*Name*}" }, { "childtype": "BULLETS", "fields": [ { "fieldname": "Name", "fieldtype": "Text", "sortkeynum": 1 }, { "fieldname": "Name_src", "fieldtype": "Text", "sortkeynum": 2 } ], "formathtml": true, "formatname": "BULLET_HEADING", "outputlines": [ "{*Name*}" ], "spacebetween": false, "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "HtmlText", "sortkeynum": 1 }, { "fieldname": "Name_src", "fieldtype": "HtmlText", "sortkeynum": 2 } ], "formathtml": true, "formatname": "HEADINGS", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "HtmlText", "sortkeynum": 1 }, { "fieldname": "Name_src", "fieldtype": "Text", "sortkeynum": 2 }, { "fieldname": "Text", "fieldtype": "HtmlText", "lines": 8 }, { "fieldname": "Text_src", "fieldtype": "HtmlText", "lines": 8 } ], "formathtml": true, "formatname": "HEAD_PARA", "icon": "bullet_2", "outputlines": [ "
  • {*Name*} - {*Text*}
  • " ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text", "sortkeynum": 1 }, { "fieldname": "Name_src", "fieldtype": "Text", "sortkeynum": 2 }, { "fieldname": "Text", "fieldtype": "HtmlText", "lines": 8 }, { "fieldname": "Text_src", "fieldtype": "HtmlText", "lines": 8 } ], "formatname": "PARAGRAPH", "icon": "bullet_2", "outputlines": [ "{*Text*}" ], "titleline": "{*Name*}" } ], "nodes": [ { "children": [], "data": { "Name": "Minimize to system tray option", "Text": "A minimize to system tray option was added to General Options (under Features Available). If enabled, it adds a TreeLine system tray icon to toggle application display and hides the taskbar entry when TreeLine is minimized." }, "format": "BULLETS", "uid": "014e1392305b11e9ab99a44cc8e97404" }, { "children": [], "data": { "Name": "Automatic clone creation", "Text": "Cloned nodes can be created automatically from all identical nodes by using the \"Data > Clone All Matched Nodes\" command." }, "format": "BULLETS", "uid": "04a868f4bb0611e7aea13417ebd53aeb" }, { "children": [], "data": { "Name": "Multiple top-level nodes", "Text": "Multiple top-level (root) nodes are now permitted. When no nodes are selected in the tree (by clicking on a blank area or Ctrl clicking to unselect), the right-hand view will show information about all of the top-level nodes." }, "format": "BULLETS", "uid": "04da8386ba4811e7b3de3417ebd53aeb" }, { "children": [], "data": { "Name": "Updating multiple windows", "Text": "Properly update multiple windows after drag and drop tree changes." }, "format": "BULLETS", "uid": "0906c05bdc8f11ea94fbac675dac20af" }, { "children": [], "data": { "Name": "\u041f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440 \u043f\u0435\u0447\u0430\u0442\u0438", "Name_src": "Print Preview", "Text": "\u0412 \u043e\u043a\u043d\u0435 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0440\u0430\u0441\u043f\u0435\u0447\u0430\u0442\u0430\u043d\u043d\u044b\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u0441 \u0442\u0435\u043a\u0443\u0449\u0438\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u0435\u0447\u0430\u0442\u0438. \u041e\u043d \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d \u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430, \u0447\u0442\u043e\u0431\u044b \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0434\u0435\u0442\u0430\u043b\u0435\u0439, \u0438\u043b\u0438 \u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b \u043f\u043e \u0436\u0435\u043b\u0430\u043d\u0438\u044e. \u0412 \u043e\u043a\u043d\u0435 \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u0435\u0447\u0430\u0442\u0438\u00bb \u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0435\u0447\u0430\u0442\u0438.", "Text_src": "The Print Preview window shows how the printout will look with current print settings. It can be dragged larger to show more detail, or the zoom settings can be changed. It also includes buttons for the Print Setup dialog and for printing." }, "format": "HEAD_PARA", "uid": "0a0d866469dd11eb9819001fd026534b" }, { "children": [], "data": { "Name": "Reduce windows install size", "Text": "Some unnecessary libraries were eliminated from the Windows installer to reduce download sizes and installed space requirements." }, "format": "BULLETS", "uid": "10c539e2305c11e9a392a44cc8e97404" }, { "children": [], "data": { "Name": "\u0410\u043f\u0435\u0447\u0430\u0442\u044c \u0432 PDF", "Name_src": "Print to PDF", "Text": "\u042d\u0442\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 \u043f\u0443\u0442\u044c \u0438 \u0438\u043c\u044f \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0444\u0430\u0439\u043b\u0430 \u0432 PDF \u0444\u043e\u0440\u043c\u0430\u0442. \u041f\u0440\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u0435\u043a\u0443\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0440\u0438\u043d\u0442\u0435\u0440\u0430.", "Text_src": "This command prompts for a path and file name to export a PDF file. It uses the current printer settings." }, "format": "HEAD_PARA", "uid": "12aaf67e69dd11eb9d47001fd026534b" }, { "children": [], "data": { "Name": "Right view update", "Text": "Properly update the right-hand views after using a new window command." }, "format": "BULLETS", "uid": "145bd91a334c11e896b1d66a6ab671cb" }, { "children": [], "data": { "Name": "Avoid unfocused title edit", "Text": "A click on a tree node to restore tree focus no longer starts editing the node title." }, "format": "BULLETS", "uid": "15da7fde786a11e881c8a44cc8e97404" }, { "children": [], "data": { "Name": "Remove redundant newlines in files", "Text": "Some redundant newline characters were removed from text storage in TreeLine files." }, "format": "BULLETS", "uid": "192373c6305511e9ab21a44cc8e97404" }, { "children": [], "data": { "Name": "Restore data editor cursor & scroll positions", "Text": "Restore the cursor and scroll positions of data editors when the editors are re-created after focus changes." }, "format": "BULLETS", "uid": "194b052fe5d811e9a0d1a44cc8e97404" }, { "children": [ "3e749de3e5d811e98227a44cc8e97404", "194b0537e5d811e989a1a44cc8e97404", "194b0534e5d811e985f6a44cc8e97404" ], "data": { "Name": "October 6, 2019 - Release 3.1.2 (stable release)" }, "format": "HEADINGS", "uid": "194b0533e5d811e9b5fea44cc8e97404" }, { "children": [ "8cdb2406e5df11e9a06da44cc8e97404", "8e8e418ae5dc11e98404a44cc8e97404", "9139627ee5db11e98a21a44cc8e97404", "194b0536e5d811e991b3a44cc8e97404", "fcc1b718e5df11e9a7f9a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "194b0534e5d811e985f6a44cc8e97404" }, { "children": [], "data": { "Name": "Treepad import", "Text": "Fix error due to character encoding when importing files from Treepad." }, "format": "BULLETS", "uid": "194b0536e5d811e991b3a44cc8e97404" }, { "children": [ "194b052fe5d811e9a0d1a44cc8e97404", "ea0c9b24e79911e98abe7054d2175f18", "4212597ee5e011e99b51a44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "194b0537e5d811e989a1a44cc8e97404" }, { "children": [], "data": { "Name": "Enable evaluate HTML tags option", "Text": "The Evaluate HTML tags control was enabled for date, time, boolean and math fields. This allows HTML tags to be evaluated or ignored in more field types." }, "format": "BULLETS", "uid": "1b73aaf4305811e98bb7a44cc8e97404" }, { "children": [], "data": { "Name": "Remove unique ID", "Text": "To improve efficiency, user visible node unique IDs that depend on the node's data have been removed." }, "format": "BULLETS", "uid": "1d015318bb0511e7a2ac3417ebd53aeb" }, { "children": [], "data": { "Name": "Reuse TreeLine windows", "Text": "When a file is opened in an existing window, the window is now reused (not just replaced) to eliminate flashing." }, "format": "BULLETS", "uid": "1e3a82e4bb0411e7b7f33417ebd53aeb" }, { "children": [], "data": { "Name": "Current date/time math field references", "Text": "Added support for current date and time references to math fields. Special field names ({*Now_Date*}, {*Now_Time*} and {*Now_Date_Time*}) must be manually typed in equations." }, "format": "BULLETS", "uid": "221ca8f0305911e99f3fa44cc8e97404" }, { "children": [], "data": { "Name": "German outline nuimbering", "Text": "Add support for German outline numbering using double letters in some levels (thanks to Teresa M)." }, "format": "BULLETS", "uid": "228fa647dc8c11eab28aac675dac20af" }, { "children": [], "data": { "Name": "Empty data edit views", "Text": "Fix a bug in Data Edit views when no fields are visible due to hidden numbering or math fields." }, "format": "BULLETS", "uid": "23b9a763dc8b11ea9dafac675dac20af" }, { "children": [], "data": { "Name": "Save as without filename", "Text": "Fix a minor bug affecting default directories for save-as and export commands when there is not already a file name set." }, "format": "BULLETS", "uid": "25ab9320482011e989f27054d2175f18" }, { "children": [], "data": { "Name": "Limit installer deletions", "Text": "In the Windows installer, improve the deletion of files from older versions and avoid problems if installing into a directory shared with other applications." }, "format": "BULLETS", "uid": "2767e530e80411e8aec9a44cc8e97404" }, { "children": [], "data": { "Name": "Math field restrictions", "Text": "Update math field equation restrictions to work with Python 3.8." }, "format": "BULLETS", "uid": "27950877dc8a11ea8902ac675dac20af" }, { "children": [], "data": { "Name": "Option to keep inaccessible recent files", "Text": "A new general option controls whether inaccessible files are removed from the recent file list at startup. The files are removed by default, but this can be changed to avoid losing listings of files stored on removable drives." }, "format": "BULLETS", "uid": "283565ba334211e8a34bd66a6ab671cb" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u044c \u041d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 (Breadcrumb View)", "Name_src": "Breadcrumb View", "Text": "\u041d\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0438 \u043f\u0440\u0435\u0434\u043a\u0438 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \u041f\u0430\u043d\u0435\u043b\u044c \u043f\u0443\u0441\u0442\u0430, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u043d\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u0438\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043b\u043e\u0432. \u041f\u043e \u0449\u0435\u043b\u0447\u043a\u0443 \u043c\u044b\u0448\u0438 \u043d\u0430 \u0443\u0437\u043b\u0430\u0445 \u043f\u0440\u0435\u0434\u043a\u043e\u0432, \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0445 \u0441\u0438\u043d\u0438\u043c \u0446\u0432\u0435\u0442\u043e\u043c, \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u044d\u0442\u0438\u043c \u0443\u0437\u043b\u0430\u043c.", "Text_src": "The top pane shows the parent and ancestors of the selected node. It is blank if no nodes or multiple nodes are selected. Ancestors with blue text can be clicked to select those nodes." }, "format": "HEAD_PARA", "uid": "28f8844ab58711e79d173417ebd53aeb" }, { "children": [], "data": { "Name": "Conditional type copy/paste & drag/drop", "Text": "Fixed problems with copy / paste and drag / drop on nodes with conditional type settings." }, "format": "BULLETS", "uid": "299ba9e4334a11e881a6d66a6ab671cb" }, { "children": [], "data": { "Name": "Type structure visualization", "Text": "A new Show Configuration Structure command was added to the Data menu. This opens a read-only visualization of complex type structures as another TreeLine file." }, "format": "BULLETS", "uid": "2c9ba0c832ed11e9bf7f7054d2175f18" }, { "children": [], "data": { "Name": "Pretty print output", "Text": "An indent (pretty print) output option was added to General Options (under Features Available). This makes saved TreeLine JSON files easier for humans to read at the expense of somewhat larger file sizes." }, "format": "BULLETS", "uid": "2d4430dc305711e9a33aa44cc8e97404" }, { "children": [], "data": { "Name": "Open with bad references", "Text": "TreeLine files with invalid child references can now be opened. A warning message is given about the missing child nodes in the corrupt file." }, "format": "BULLETS", "uid": "2df5b030bbf711e88a1ca44cc8e97404" }, { "children": [], "data": { "Name": "\u041f\u043e\u0440\u0442\u044b \u043d\u0430 MacOs", "Name_src": "MacPorts", "Text": "\u0421\u043c. \u041f\u043e\u0440\u0442\u044b \u043d\u0430 MacOs \u0434\u043b\u044f \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0435\u0433\u043e \u043f\u043e\u0440\u0442\u0430 \u043d\u0430 macOS.", "Text_src": "See MacPorts for a third-party port to macOS." }, "format": "PARAGRAPH", "uid": "2fa1be1fdc9511eaa00dac675dac20af" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 HTML", "Name_src": "Live HTML Export", "Text": "\u041f\u0440\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0435 \u0432 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0439 HTML \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0432 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u0443\u0437\u043b\u0430\u043c\u0438 \u0438 \u043f\u0430\u043d\u0435\u043b\u044c\u044e \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432.", "Text_src": "A live tree HTML export creates an interactive view with expandable nodes and a descendant output pane." }, "format": "BULLETS", "uid": "31304c06792b11e888cfa44cc8e97404" }, { "children": [], "data": { "Name": "Restoring window geometry", "Text": "Fix issues with restoring window geometry with multiple monitors and changing configurations." }, "format": "BULLETS", "uid": "35d0914edc8911eab202ac675dac20af" }, { "children": [], "data": { "Name": "Multiple paste commands", "Text": "New paste commands have been added for adding nodes before and after siblings. There are also multiple paste commands for adding clones of nodes." }, "format": "BULLETS", "uid": "39c001f0bb0311e79e793417ebd53aeb" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is a major rewrite of TreeLine. Once it becomes more stable, it will be released as TreeLine version 3.0.0. The 2.1.x unstable series is being discontinued (no stable 2.2.0 release is planned)." }, "format": "BULLETS", "uid": "3d2bb12eba3c11e79b223417ebd53aeb" }, { "children": [], "data": { "Name": "Chinese translation", "Text": "Add a simplified Chinese GUI translation (thanks to Qu Ray for translating)." }, "format": "BULLETS", "uid": "3e749de1e5d811e9a22ba44cc8e97404" }, { "children": [ "3e749de1e5d811e9a22ba44cc8e97404", "cef1d9fee5de11e998dea44cc8e97404" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "3e749de3e5d811e98227a44cc8e97404" }, { "children": [], "data": { "Name": "Time field AM/PM", "Text": "Now forces references to AM/PM in time field formats to be output regardless of system locale settings." }, "format": "BULLETS", "uid": "40ec6d5cbbf711e8bb93a44cc8e97404" }, { "children": [], "data": { "Name": "Outline numbering", "Text": "Change lettered outline numbering sequences to match standards. The sequences change from ...Y, Z, AA, AB, AC... to ...Y, Z, AA, BB, CC..." }, "format": "BULLETS", "uid": "4212597ee5e011e99b51a44cc8e97404" }, { "children": [], "data": { "Name": "Title list select in tree command", "Text": "A Select in Tree command was added to the Title List's right-click context menu. It selects the node corresponding to the current line in the Title List editor. This makes it easier to edit or add children to an item." }, "format": "BULLETS", "uid": "42fb4166305a11e99fd7a44cc8e97404" }, { "children": [], "data": { "Name": "Title edit mouse move", "Text": "Fixed node title editing errors caused by moving the mouse to a data edit box with the title edit still active." }, "format": "BULLETS", "uid": "45491730786a11e8b8e2a44cc8e97404" }, { "children": [], "data": { "Name": "Enter key selects current node", "Text": "The enter key now selects a tree node after the first title letter(s) are typed to make it current (shown with a box around the title)." }, "format": "BULLETS", "uid": "456aa5ca793111e89a30a44cc8e97404" }, { "children": [ "66faed8adc9411ea965eac675dac20af", "d8a76c1fdc9411eaab2dac675dac20af" ], "data": { "Name": "macOS" }, "format": "BULLET_HEADING", "uid": "460699ebdc9411ea89afac675dac20af" }, { "children": [], "data": { "Name": "Dark theme option", "Text": "An optional dark color theme was added to General Options (under Appearances)." }, "format": "BULLETS", "uid": "46f3d0a4305e11e9892fa44cc8e97404" }, { "children": [], "data": { "Name": "Relative paths", "Text": "Avoid issues resolving relative paths between different Windows drive letters in external link fields." }, "format": "BULLETS", "uid": "46fc4054334b11e89299d66a6ab671cb" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is a major rewrite of TreeLine. Once it becomes fully stable, it will be released as TreeLine version 3.0.0." }, "format": "BULLETS", "uid": "4bc47247786711e88b26a44cc8e97404" }, { "children": [ "4bc47249786711e8a3d5a44cc8e97404", "4bc4724c786711e8a8d9a44cc8e97404", "4bc4724f786711e89bdca44cc8e97404" ], "data": { "Name": "June 30, 2018 - Release 2.9.2 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "4bc47248786711e8a8bfa44cc8e97404" }, { "children": [ "4bc4724a786711e8a4dda44cc8e97404", "4bc47247786711e88b26a44cc8e97404", "4bc4724b786711e895e2a44cc8e97404" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "4bc47249786711e8a3d5a44cc8e97404" }, { "children": [], "data": { "Name": "Development snapshot", "Text": "This is a development snapshot of TreeLine that should be considered a release candidate for an upcoming stable release. Many bugs have been fixed. User testing and bug reports are appreciated." }, "format": "BULLETS", "uid": "4bc4724a786711e8a4dda44cc8e97404" }, { "children": [], "data": { "Name": "Translations", "Text": "A GUI translations is available in German. All other translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "4bc4724b786711e895e2a44cc8e97404" }, { "children": [ "57c4de74786911e89c3fa44cc8e97404", "71b708ac786911e88d64a44cc8e97404", "a7d7f61e786911e89bbca44cc8e97404", "15da7fde786a11e881c8a44cc8e97404", "456aa5ca793111e89a30a44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "4bc4724c786711e8a8d9a44cc8e97404" }, { "children": [ "e4fc680a786911e899d3a44cc8e97404", "45491730786a11e8b8e2a44cc8e97404", "f011a5d8786911e8ace3a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "4bc4724f786711e89bdca44cc8e97404" }, { "children": [], "data": { "Name": "Multi-session controls", "Text": "Fix problems detecting existing TreeLine sessions when opening files (mostly in Linux)." }, "format": "BULLETS", "uid": "5337587ddc8811eaaaedac675dac20af" }, { "children": [], "data": { "Name": "Clone removal", "Text": "The new \"Data > Detach Clones\" command converts cloned nodes in selected branches back into independent nodes." }, "format": "BULLETS", "uid": "5647bc8cbb0611e783853417ebd53aeb" }, { "children": [], "data": { "Name": "German translation", "Text": "The German GUI translation was updated (thanks to Maria Seliger)." }, "format": "BULLETS", "uid": "57c4de74786911e89c3fa44cc8e97404" }, { "children": [], "data": { "Name": "Linux menus", "Text": "Added a desktop specification file to the Linux installer for desktop environment menu support." }, "format": "BULLETS", "uid": "58dddee4010f11e88925d66a6ab671cb" }, { "children": [], "data": { "Name": "\u041d\u0430\u0437\u043d\u0430\u0447\u0430\u0435\u043c\u044b\u0435 \u0442\u0438\u043f\u044b", "Name_src": "Setting types", "Text": "\u041a\u0430\u0436\u0434\u043e\u043c\u0443 \u0443\u0437\u043b\u0443 \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0438\u043f\u0430.", "Text_src": "Each tree node can be set to a type format independently." }, "format": "BULLETS", "uid": "5c1d58ac792a11e8b78ca44cc8e97404" }, { "children": [], "data": { "Name": "Category level swap", "Text": "A new \"Swap Category Levels\" command swaps child and grandchild nodes beneath a selected node. A child node with multiple nodes under it will become cloned under each one. Any existing grandchild clones will become individual nodes with multiple children." }, "format": "BULLETS", "uid": "5c90e0b0bb0611e78e443417ebd53aeb" }, { "children": [], "data": { "Name": "\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b", "Name_src": "Cloned nodes", "Text": "\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b (\u043e\u0434\u043d\u0438 \u0438 \u0442\u0435 \u0436\u0435 \u0443\u0437\u043b\u044b \u0441 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f\u043c\u0438 / \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438) \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0438\u043b\u0438 \u043f\u0443\u0442\u0435\u043c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432.", "Text_src": "Cloned nodes (the same nodes with multiple parents/locations) can be created using special paste commands or by automatically matching identical nodes." }, "format": "BULLETS", "uid": "5f12f768b32c11e7a41a3417ebd53aeb" }, { "children": [], "data": { "Name": "Library updates", "Text": "Update the libraries used to build the Windows binaries to Python 3.8 and Qt/PyQt 5.14." }, "format": "BULLETS", "uid": "603e11fadf2011eaa12e7054d2175f18" }, { "children": [ "2fa1be1fdc9511eaa00dac675dac20af" ], "data": { "Name": "macOS" }, "format": "BULLET_HEADING", "uid": "611e03ffdc9411ea930eac675dac20af" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u0444\u0430\u0439\u043b\u044b TreeLine", "Name_src": "TreeLine Export", "Text": "\u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u0444\u0430\u0439\u043b\u044b, \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0435 \u0441\u043e \u0441\u0442\u0430\u0440\u044b\u043c\u0438 \u0432\u0435\u0440\u0441\u0438\u044f\u043c\u0438 TreeLine (1.x \u0438 2.x), \u0438\u043c\u0435\u044e\u0449\u0438\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u00ab.trl\u00bb. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u043e\u0432\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c\u0438 \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u043a\u043e\u0440\u043d\u0435\u0432\u044b\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438, \u043f\u0440\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u044b \u043d\u0435 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e. \u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 TreeLine \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0435\u0432\u044c\u044f TreeLine, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0444\u0430\u0439\u043b \u0441\u0442\u0430\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u0435\u0442\u0432\u0438 \u0434\u0435\u0440\u0435\u0432\u0430.", "Text_src": "Files can be exported that are compatible with older versions of TreeLine (1.x and 2.x), with a \".trl\" file extension. Some newer features, such as cloned nodes and multiple root nodes may not be completely preserved. TreeLine subtrees can also be exported to save just selected branches of the tree to a file using the current TreeLine version." }, "format": "HEAD_PARA", "uid": "65289b36b97611e783eb3417ebd53aeb" }, { "children": [], "data": { "Name": "Custom time dialog", "Text": "Added a custom time select dialog box for editing Time and TimeDate fields." }, "format": "BULLETS", "uid": "653f2f90334c11e8a7c9d66a6ab671cb" }, { "children": [], "data": { "Name": "Printing long nodes", "Text": "Multiple issues with printing long nodes were fixed." }, "format": "BULLETS", "uid": "6610203dd2c111e8a95ad66a6ab671cb" }, { "children": [ "66102040d2c111e8a210d66a6ab671cb", "66102041d2c111e8bd85d66a6ab671cb" ], "data": { "Name": "October 20, 2018 - Release 3.0.2 (stable release)" }, "format": "HEADINGS", "uid": "6610203fd2c111e8b033d66a6ab671cb" }, { "children": [ "66102049d2c111e8bb55d66a6ab671cb" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "66102040d2c111e8a210d66a6ab671cb" }, { "children": [ "66102043d2c111e88d57d66a6ab671cb", "6610203dd2c111e8a95ad66a6ab671cb", "66102048d2c111e89f4cd66a6ab671cb" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "66102041d2c111e8bd85d66a6ab671cb" }, { "children": [], "data": { "Name": "Windows printing", "Text": "Fixed nonfunctional printing commands under Windows by building the Windows binary using PyInstaller rather than cx_Freeze." }, "format": "BULLETS", "uid": "66102043d2c111e88d57d66a6ab671cb" }, { "children": [], "data": { "Name": "Blanks as zeros", "Text": "Fixed problems saving files when the blanks as zeros property was changed for math fields." }, "format": "BULLETS", "uid": "66102048d2c111e89f4cd66a6ab671cb" }, { "children": [], "data": { "Name": "Python 3.7", "Text": "Upgraded the Windows binary from Python 3.6 to Python 3.7." }, "format": "BULLETS", "uid": "66102049d2c111e8bb55d66a6ab671cb" }, { "children": [], "data": { "Name": "\u041d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f", "Name_src": "Not supported", "Text": "\u0412 \u0441\u0438\u0434\u0443 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u044f \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u043e\u0432 Mac \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f TreeLine \u043d\u0430 macOS \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f.", "Text_src": "Due to a lack of Macs for testing, TreeLine on macOS is not formally supported." }, "format": "BULLETS", "uid": "66faed8adc9411ea965eac675dac20af" }, { "children": [ "67e95a5fbbf611e8b8bda44cc8e97404", "67e95a60bbf611e8a80ca44cc8e97404" ], "data": { "Name": "September 29, 2018 - Release 3.0.1 (stable release)" }, "format": "HEADINGS", "uid": "67e95a5bbbf611e891f7a44cc8e97404" }, { "children": [ "f966db0cc23f11e8b80fd66a6ab671cb", "67e95a61bbf611e8989ca44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "67e95a5fbbf611e8b8bda44cc8e97404" }, { "children": [ "67e95a64bbf611e8960fa44cc8e97404", "2df5b030bbf711e88a1ca44cc8e97404", "dc700fb4c24211e8b88dd66a6ab671cb", "40ec6d5cbbf711e8bb93a44cc8e97404", "9550a81ac24111e89029d66a6ab671cb", "71e2f25cc24211e88524d66a6ab671cb", "a757f64ac24211e8a95fd66a6ab671cb", "bdc8628ec2bd11e889e57054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "67e95a60bbf611e8a80ca44cc8e97404" }, { "children": [], "data": { "Name": "About dialog text box", "Text": "Added a read-only text box to the Help > About dialog to allow copying of the version and library information." }, "format": "BULLETS", "uid": "67e95a61bbf611e8989ca44cc8e97404" }, { "children": [], "data": { "Name": "Old file import", "Text": "Fixed a problem opening old TreeLine files that had format changes in File Info fields." }, "format": "BULLETS", "uid": "67e95a64bbf611e8960fa44cc8e97404" }, { "children": [], "data": { "Name": "Data in config structure", "Text": "Added many Show Configuration Structure data fields to show detailed settings for type formats and field formats.." }, "format": "BULLETS", "uid": "6a6067d4482011e989f27054d2175f18" }, { "children": [], "data": { "Name": "Select top node at open", "Text": "The top root node is now selected at file open if there is not a recent selection state to restore. Previously these files opened with no selection, which could cause confusion." }, "format": "BULLETS", "uid": "6a98186e305c11e99fbfa44cc8e97404" }, { "children": [], "data": { "Name": "Insert date command", "Text": "Add an Insert Date command that adds a timestamp to text field edit boxes." }, "format": "BULLETS", "uid": "6c916f15dc8c11ea9dbeac675dac20af" }, { "children": [], "data": { "Name": "Child type limits", "Text": "Child node types that are available to be set can be limited. A new pull-down list of child type limits is in the \"Type Config\" tab of the configuration dialog if the advanced functions are shown." }, "format": "BULLETS", "uid": "6dc88226bb0711e7894d3417ebd53aeb" }, { "children": [ "6df9a0c6ba3b11e7925d3417ebd53aeb", "6df9a0c9ba3b11e7a9793417ebd53aeb" ], "data": { "Name": "January 28, 2018 - Release 2.9.0 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "6df9a0c5ba3b11e78e7e3417ebd53aeb" }, { "children": [ "6df9a0c7ba3b11e7b7bd3417ebd53aeb", "3d2bb12eba3c11e79b223417ebd53aeb", "6df9a0c8ba3b11e78d783417ebd53aeb" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "6df9a0c6ba3b11e7925d3417ebd53aeb" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It could contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) is recommended for critical work." }, "format": "BULLETS", "uid": "6df9a0c7ba3b11e7b7bd3417ebd53aeb" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "6df9a0c8ba3b11e78d783417ebd53aeb" }, { "children": [ "6df9a0caba3b11e78b283417ebd53aeb", "d1d8e56eba4011e784ab3417ebd53aeb", "04da8386ba4811e7b3de3417ebd53aeb", "e6ad9f6eba4311e796bd3417ebd53aeb", "cd28e024bb0211e79c553417ebd53aeb", "1e3a82e4bb0411e7b7f33417ebd53aeb", "98132868ba4511e7b7283417ebd53aeb", "39c001f0bb0311e79e793417ebd53aeb", "04a868f4bb0611e7aea13417ebd53aeb", "5647bc8cbb0611e783853417ebd53aeb", "5c90e0b0bb0611e78e443417ebd53aeb", "6dc88226bb0711e7894d3417ebd53aeb", "7697b826bb0411e788433417ebd53aeb", "1d015318bb0511e7a2ac3417ebd53aeb", "f5983b38bb0411e795e13417ebd53aeb", "58dddee4010f11e88925d66a6ab671cb" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "6df9a0c9ba3b11e7a9793417ebd53aeb" }, { "children": [], "data": { "Name": "New file format", "Text": "TreeLine files now uses a new JSON format in place of the old XML format. This provides more flexibility for structuring new features like cloned nodes and multiple root nodes. A new file extension (\".trln) helps to distinguish these files." }, "format": "BULLETS", "uid": "6df9a0caba3b11e78b283417ebd53aeb" }, { "children": [], "data": { "Name": "\u041f\u0440\u0438\u043c\u0435\u0447\u0430\u043d\u0438\u044f \u043a \u041f\u0435\u0440\u0435\u0432\u043e\u0434\u0443", "Name_src": "Translation Notes", "Text": "\u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 Treeline \u0432\u0435\u0440\u0441\u0438\u0438 3.1.4 \u043d\u0430 \u0440\u0443\u0441\u0441\u043a\u0438\u0439 \u044f\u0437\u044b\u043a \u2014 \u0410. \u0422\u0440\u043e\u0444\u0438\u043c\u043e\u0432, 12.02.2021\u0433., 08.09.2022\u0433.\n
    \n
    \n\u0411\u043e\u043b\u044c\u0448\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u0438\u0437 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u0435\u043d\u044b \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f Windows.\n
    \n
    \n\u0422\u0430\u043a \u0436\u0435 \u043a\u0430\u043a \u0438 \u0441\u0430\u043c\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u0435\u043d \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438 \u0438 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u043d\u0430\u0434\u0435\u0436\u0434\u0435, \u0447\u0442\u043e \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u0435\u043d, \u043d\u043e \u0411\u0415\u0417 \u041a\u0410\u041a\u0418\u0425-\u041b\u0418\u0411\u041e \u0413\u0410\u0420\u0410\u041d\u0422\u0418\u0419.\n
    \n
    \n\u0412 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u043f\u043e \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u043c \u043e\u0442 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0447\u0438\u043a\u0430 \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c \u043d\u0435 \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043e:\n
      \n
    • \u0421\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 > \u0412\u044b\u0432\u043e\u0434 > \u0423\u0440\u043e\u0432\u0435\u043d\u044c \u0441\u0441\u044b\u043b\u043a\u0438\u00bb
    • \n
    • \u041a\u043d\u043e\u043f\u043a\u0438 \u00abYes\u00bb, \u00abNo\u00bb, \u00abCancel\u00bb, \u00abDiscard\u00bb \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u044b\u0445 \u043e\u043a\u043d\u0430\u0445 \u00ab\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f\u00bb, \u043e\u043a\u043d\u0435 \u00abTreeline\u00bb \u0432\u044b\u0445\u043e\u0434\u0430 \u0438\u0437 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f
    • \n
    \n
    \n\u0412 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043d\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0438\u043b\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b \u00ab\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439\u00bb.\n
    \n
    \n\u0412 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043c\u0435 \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438:\n
      \n
    • \u041f\u0443\u043d\u043a\u0442 \u00ab\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432\u0435\u0442\u0432\u0438\u00bb \u043c\u0435\u043d\u044e \u00ab\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430\u00bb \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0438 \u043e\u0434\u043d\u043e\u0439 \u00ab\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0442\u0432\u0438\u00bb, \u043e\u0434\u043d\u0430\u043a\u043e \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u0441\u044f, \u0442.\u043a. \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u0430\u0432\u0442\u043e\u0440\u043e\u043c \u0432 \u043d\u043e\u0432\u043e\u043c \u0440\u0435\u043b\u0438\u0437\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b
    • \n
    • \u041f\u0443\u043d\u043a\u0442 \u00ab\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b\u00bb \u043c\u0435\u043d\u044e \u00ab\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430\u00bb \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u0438 \u043e\u0434\u043d\u043e\u0433\u043e \u00ab\u0412\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430\u00bb, \u043e\u0434\u043d\u0430\u043a\u043e \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u043d\u0435 \u043c\u0435\u043d\u044f\u043b\u0441\u044f, \u0442.\u043a. \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e \u043e\u0448\u0438\u0431\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0430 \u0430\u0432\u0442\u043e\u0440\u043e\u043c \u0432 \u043d\u043e\u0432\u043e\u043c \u0440\u0435\u043b\u0438\u0437\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b
    • \n
    \n
    \n\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u0438 \u043d\u0435\u043e\u0447\u0435\u0432\u0438\u0434\u043d\u044b\u0435 \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438 [\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b ...], \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c\u0438 \u0448\u0440\u0438\u0444\u0442\u043e\u043c \u043a\u0440\u0430\u0441\u043d\u043e\u0433\u043e \u0446\u0432\u0435\u0442\u0430.\n
    \n
    \n\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432\u043d\u0435\u0441\u0435\u043d\u043d\u044b\u0439 \u0432 \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0442\u0435\u043a\u0441\u0442 \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u043d\u044b\u0435 \u0441\u043a\u043e\u0431\u043a\u0438 \u2014 [].\n" }, "format": "PARAGRAPH", "uid": "6e4dd051678a11eb8f00001fd026534b" }, { "children": [], "data": { "Name": "Maintain expanded nodes", "Text": "The expand/collapse status of nearby nodes is maintained while editing the node structure. This includes adding, deleting, moving and indenting nodes." }, "format": "BULLETS", "uid": "71b708ac786911e88d64a44cc8e97404" }, { "children": [], "data": { "Name": "Complex data menu commands", "Text": "Fixed various errors when applying advanced clone and category commands from the Data menu to complex node structures." }, "format": "BULLETS", "uid": "71e2f25cc24211e88524d66a6ab671cb" }, { "children": [], "data": { "Name": "Date and time formats", "Text": "The Date, Time and DateTime fields have new format strings that enable extra text to be added to the date output." }, "format": "BULLETS", "uid": "7697b826bb0411e788433417ebd53aeb" }, { "children": [], "data": { "Name": "Number field formatting", "Text": "Fixed problems with number field formatting when using a \",\" radix with exponents." }, "format": "BULLETS", "uid": "7716c96e334a11e896bfd66a6ab671cb" }, { "children": [], "data": { "Name": "Math field expressions", "Text": "Evaluate math expressions contained in fields that are referenced by math field equations. " }, "format": "BULLETS", "uid": "7a9ace43dc8a11ea9e9bac675dac20af" }, { "children": [], "data": { "Name": "\u041b\u043e\u043a\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438", "Name_src": "Translations", "Text": "\u0412 TreeLine \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u044b \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043d\u0430 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u044b\u0439 \u043a\u0438\u0442\u0430\u0439\u0441\u043a\u0438\u0439, \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u0438\u0439, \u043d\u0435\u043c\u0435\u0446\u043a\u0438\u0439, \u0440\u0443\u0441\u0441\u043a\u0438\u0439 \u0438 \u0438\u0441\u043f\u0430\u043d\u0441\u043a\u0438\u0439 \u044f\u0437\u044b\u043a\u0438. \u0415\u0441\u043b\u0438 \u044f\u0437\u044b\u043a\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u041e\u0421 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u044b \u043a \u043a\u043e\u043c\u0430\u043d\u0434\u0435, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0449\u0435\u0439 TreeLine, \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u00ab--lang xx\u00bb, \u0433\u0434\u0435 \u00abxx\u00bb - \u044d\u0442\u043e \u0434\u0432\u0443\u0445\u0431\u0443\u043a\u0432\u0435\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u044f\u0437\u044b\u043a\u0430 (\u00abzh\u00bb, \u00aben\u00bb, \u00abde\u00bb, \u00abru\u00bb \u043b\u0438 \u00abes\u00bb).", "Text_src": "Translations of the TreeLine GUI are available in German and Spanish. The translation should load automatically if the OS locale is properly set. Alternatively, \"--lang xx\" can be appended to the command that starts TreeLine, where \"xx\" is the two-letter language code (\"en\", \"de\" or \"es\")." }, "format": "HEAD_PARA", "uid": "7e9b3b88c24511e896c7d66a6ab671cb" }, { "children": [ "7ffeb672dc8711ea86ddac675dac20af", "7ffeb670dc8711ea81aeac675dac20af", "7ffeb66edc8711eaaa13ac675dac20af" ], "data": { "Name": "August 16, 2020 - Release 3.1.3 (stable release)" }, "format": "HEADINGS", "uid": "7ffeb66ddc8711ea9a87ac675dac20af" }, { "children": [ "d9119485dc8711ea92dcac675dac20af", "8d9c1717dc8811ea9c40ac675dac20af", "cf9c139fdc8e11ea8261ac675dac20af", "88bb6300dc8e11ea9a73ac675dac20af", "b6a4a6bddc8911ea8612ac675dac20af", "23b9a763dc8b11ea9dafac675dac20af", "0906c05bdc8f11ea94fbac675dac20af", "35d0914edc8911eab202ac675dac20af", "f2a0c0a1dc8d11ea8921ac675dac20af", "5337587ddc8811eaaaedac675dac20af" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "7ffeb66edc8711eaaa13ac675dac20af" }, { "children": [ "27950877dc8a11ea8902ac675dac20af", "c1f8dca5dc9511ea8f76ac675dac20af", "603e11fadf2011eaa12e7054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "7ffeb670dc8711ea81aeac675dac20af" }, { "children": [ "dca5b84fdc8a11eab098ac675dac20af", "6c916f15dc8c11ea9dbeac675dac20af", "7a9ace43dc8a11ea9e9bac675dac20af", "228fa647dc8c11eab28aac675dac20af" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "7ffeb672dc8711ea86ddac675dac20af" }, { "children": [ "800a0972305111e9a7fea44cc8e97404", "f7bbd909305111e9be43a44cc8e97404", "800a0975305111e9a018a44cc8e97404", "800a0976305111e9bd43a44cc8e97404" ], "data": { "Name": "February 20, 2019 - Release 3.1.0 (beta release)" }, "format": "HEADINGS", "uid": "800a0971305111e991cda44cc8e97404" }, { "children": [ "800a0973305111e9b7b9a44cc8e97404", "800a0974305111e99f0fa44cc8e97404" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "800a0972305111e9a7fea44cc8e97404" }, { "children": [], "data": { "Name": "Beta release", "Text": "This is a beta release of TreeLine. Some new features have not been extensively tested, but major bugs are unlikely. Testing and bug reports are appreciated, but those with very critical work should consider using the stable release (TreeLine 3.0.x)." }, "format": "BULLETS", "uid": "800a0973305111e9b7b9a44cc8e97404" }, { "children": [], "data": { "Name": "Translations", "Text": "GUI translations are available in German and Spanish, but they still require minor updates to cover recent changes. Volunteers are also needed to update or create translations in additional languages." }, "format": "BULLETS", "uid": "800a0974305111e99f0fa44cc8e97404" }, { "children": [ "6a98186e305c11e99fbfa44cc8e97404", "800a0977305111e98c38a44cc8e97404", "10c539e2305c11e9a392a44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "800a0975305111e9a018a44cc8e97404" }, { "children": [ "800a097a305111e9950ba44cc8e97404", "192373c6305511e9ab21a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "800a0976305111e9bd43a44cc8e97404" }, { "children": [], "data": { "Name": "Gray out data edit view math fields", "Text": "Non-editable math fields in the Data Edit view show as gray when the mouse hovers over them." }, "format": "BULLETS", "uid": "800a0977305111e98c38a44cc8e97404" }, { "children": [], "data": { "Name": "Titles from HTML text fields", "Text": "Fixed the truncation of node titles that are generated from the first line of HTML Text fields." }, "format": "BULLETS", "uid": "800a097a305111e9950ba44cc8e97404" }, { "children": [], "data": { "Name": "Numbering", "Text": "Fix incorrect numbering updates in some situations with mixed node types." }, "format": "BULLETS", "uid": "84b24010482211e989f27054d2175f18" }, { "children": [], "data": { "Name": "Circular math errors", "Text": "Fix problems opening files that contain circular reference errors in math fields." }, "format": "BULLETS", "uid": "88bb6300dc8e11ea9a73ac675dac20af" }, { "children": [], "data": { "Name": "Truncated text export", "Text": "Fix a bug that truncated plain text exports after the first line." }, "format": "BULLETS", "uid": "8cdb2406e5df11e9a06da44cc8e97404" }, { "children": [], "data": { "Name": "Find & replace error", "Text": "Avoid an application error when a Find and Replace command causes fields to contain invalid data." }, "format": "BULLETS", "uid": "8d9c1717dc8811ea9c40ac675dac20af" }, { "children": [], "data": { "Name": "Title list select in tree", "Text": "Enable the title list view's select in tree context menu to be used on new child nodes." }, "format": "BULLETS", "uid": "8e8e418ae5dc11e98404a44cc8e97404" }, { "children": [], "data": { "Name": "Copy command errors", "Text": "Fix errors shown when using copy commands after closing TreeLine windows." }, "format": "BULLETS", "uid": "90dbc4e4334b11e892d0d66a6ab671cb" }, { "children": [], "data": { "Name": "Dark mode tooltips", "Text": "Modify dark mode colors to make tool tips visible." }, "format": "BULLETS", "uid": "9139627ee5db11e98a21a44cc8e97404" }, { "children": [], "data": { "Name": "Purge old field data", "Text": "Data from fields that were removed from the configuration is now purged when a file is saved. This avoids missing matches in the Clone All Matched Nodes command." }, "format": "BULLETS", "uid": "9550a81ac24111e89029d66a6ab671cb" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 \u0444\u0430\u0439\u043b\u043e\u0432 TreeLine \u0421\u0442\u0430\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438", "Name_src": "Old TreeLine Import", "Text": "\u0424\u0430\u0439\u043b\u044b \u0438\u0437 \u0431\u043e\u043b\u0435\u0435 \u0441\u0442\u0430\u0440\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 TreeLine (1.x \u0438\u043b\u0438 2.x) \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b. \u042d\u0442\u0438 \u0444\u0430\u0439\u043b\u044b \u0431\u043e\u043b\u0435\u0435 \u0441\u0442\u0430\u0440\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u0438\u043c\u0435\u044e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442 XML \u0438 \u043e\u0431\u044b\u0447\u043d\u043e \u0438\u043c\u0435\u044e\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \".trl\" (\u0444\u0430\u0439\u043b\u044b \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438\u043c\u0435\u044e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442 JSON \u0441 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435\u043c \".trln\"). \u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438\u043c\u043f\u043e\u0440\u0442\u0430, \u044d\u0442\u0438 \u0441\u0442\u0430\u0440\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0431\u0435\u0437 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0424\u0430\u0439\u043b > \u041e\u0442\u043a\u0440\u044b\u0442\u044c\u00bb.", "Text_src": "Files from older versions of TreeLine (1.x or 2.x) can be imported. These files are in XML format and generally have a \".trl\" file extension (current files are in JSON format with a \".trln\" file extension). Unlike other file imports, these older files will import without showing the import dialog box when using the \"File > Open\" command." }, "format": "HEAD_PARA", "uid": "95547c38b97411e7a42a3417ebd53aeb" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is a major rewrite of TreeLine. Once it becomes more stable, it will be released as TreeLine version 3.0.0. The 2.1.x unstable series is being discontinued (no stable 2.2.0 release is planned)." }, "format": "BULLETS", "uid": "95a6e905333f11e886edd66a6ab671cb" }, { "children": [ "95a6e90b333f11e8976fd66a6ab671cb", "95a6e90e333f11e88696d66a6ab671cb", "b16866da333f11e88adbd66a6ab671cb" ], "data": { "Name": "March 31, 2018 - Release 2.9.1 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "95a6e90a333f11e89efed66a6ab671cb" }, { "children": [ "95a6e90c333f11e8b766d66a6ab671cb", "95a6e905333f11e886edd66a6ab671cb", "95a6e90d333f11e8b88ed66a6ab671cb" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "95a6e90b333f11e8976fd66a6ab671cb" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It has improved but could still contain bugs. Testing and bug reports are appreciated, but those with very critical work should consider using the stable release (TreeLine 2.0.x)." }, "format": "BULLETS", "uid": "95a6e90c333f11e8b766d66a6ab671cb" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "95a6e90d333f11e8b88ed66a6ab671cb" }, { "children": [ "b1cd1f82334111e8b89ad66a6ab671cb", "dd22e382334111e894e6d66a6ab671cb", "653f2f90334c11e8a7c9d66a6ab671cb", "283565ba334211e8a34bd66a6ab671cb" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "95a6e90e333f11e88696d66a6ab671cb" }, { "children": [], "data": { "Name": "Child count equation references", "Text": "Eliminate a problem defining math field equations that include child count references." }, "format": "BULLETS", "uid": "95d970aa481f11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Native cloned nodes", "Text": "Cloned nodes now have a more native and efficient implementation. This allows the same nodes to have multiple parents. The new breadcrumb view shows a list of clones for the selected node that can be clicked to select the other instances." }, "format": "BULLETS", "uid": "98132868ba4511e7b7283417ebd53aeb" }, { "children": [], "data": { "Name": "\u041c\u0435\u043d\u044e \u00ab\u0424\u043e\u0440\u043c\u0430\u0442\u00bb (Format Menu)", "Name_src": "Format Menu", "Text": "\u0412 \u043c\u0435\u043d\u044e \u00ab\u0424\u043e\u0440\u043c\u0430\u0442\u00bb \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c\u0438 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u00ab\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb.", "Text_src": "The format menu has text formatting commands that are active when using edit boxes in the Data Edit view." }, "format": "HEAD_PARA", "uid": "997af664b58811e7ac243417ebd53aeb" }, { "children": [], "data": { "Name": "Ancestor field references", "Text": "Fixed problems with advanced ancestor field output references in some tree locations." }, "format": "BULLETS", "uid": "9a8a1400334c11e89838d66a6ab671cb" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442/\u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0444\u0430\u0439\u043b\u043e\u0432 TreeLine \u0441\u0442\u0430\u0440\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439", "Name_src": "Old TreeLine import/export", "Text": "\u041c\u043e\u0436\u043d\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0431\u043e\u043b\u0435\u0435 \u0441\u0442\u0430\u0440\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 TreeLine (2.x \u0438 1.x).", "Text_src": "Files from older versions of TreeLine (2.x and 1.x) can be imported and exported." }, "format": "BULLETS", "uid": "9bd80f34b32b11e7be613417ebd53aeb" }, { "children": [], "data": { "Name": "Portable config", "Text": "Problems with writing config files in Windows portable installations were fixed." }, "format": "BULLETS", "uid": "9c08f39de80311e8b791a44cc8e97404" }, { "children": [ "9c08f3a0e80311e8b2e0a44cc8e97404" ], "data": { "Name": "November 17, 2018 - Release 3.0.3 (stable release)" }, "format": "HEADINGS", "uid": "9c08f39ee80311e8a510a44cc8e97404" }, { "children": [ "9c08f3a1e80311e884dca44cc8e97404", "9c08f39de80311e8b791a44cc8e97404", "9c08f3a2e80311e88128a44cc8e97404", "2767e530e80411e8aec9a44cc8e97404" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "9c08f3a0e80311e8b2e0a44cc8e97404" }, { "children": [], "data": { "Name": "Child count fields", "Text": "Fixed an error when adding child count fields to the output format." }, "format": "BULLETS", "uid": "9c08f3a1e80311e884dca44cc8e97404" }, { "children": [], "data": { "Name": "Config file error handling", "Text": "Improved error handling after failing to read or write config files." }, "format": "BULLETS", "uid": "9c08f3a2e80311e88128a44cc8e97404" }, { "children": [], "data": { "Name": "\u0426\u0432\u0435\u0442\u0430", "Name_src": "Colors", "Text": "\u0426\u0432\u0435\u0442\u0430 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > Customize Colors [\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0446\u0432\u0435\u0442\u0430]\u00bb. \u041f\u043e\u043c\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0439 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u0442\u0435\u043c\u043d\u0430\u044f \u0442\u0435\u043c\u0430 \u0438\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u044b \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0446\u0432\u0435\u0442\u0430.", "Text_src": "The default GUI colors can be changed using the \"Tools > Customize Colors\" dialog. A dark theme is available, or individual colors can be selected." }, "format": "HEAD_PARA", "uid": "9ff09734dc9011ea887bac675dac20af" }, { "children": [], "data": { "Name": "Complex undo operations", "Text": "Fixed some problems with using the Undo command after complex operations." }, "format": "BULLETS", "uid": "a757f64ac24211e8a95fd66a6ab671cb" }, { "children": [], "data": { "Name": "Save state for discarded files", "Text": "The expanded/collapsed and selected tree states are now saved even if changes were discarded in the previous session." }, "format": "BULLETS", "uid": "a7d7f61e786911e89bbca44cc8e97404" }, { "children": [], "data": { "Name": "Pull-downs on repeated dialog boxes", "Text": "Fixed issues on Windows with pull-down combo boxes not working after repeatedly showing some dialogs (mostly find and filter dialogs)." }, "format": "BULLETS", "uid": "a7fa190c334911e88d18d66a6ab671cb" }, { "children": [], "data": { "Name": "\u041e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0422\u0438\u043f\u0430 \u0414\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0423\u0437\u043b\u0430", "Name_src": "Child Type Limits", "Text": "\u041f\u043e\u043c\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0442\u0438\u043f\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0443\u0437\u043b\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043c\u043e\u0436\u043d\u043e \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u044b \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432. \u041d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u0430\u00bb \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043f\u0440\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u043a\u0430\u0437\u0435 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432 \u0441\u043f\u0438\u0441\u043a\u0430\u0445 \u0442\u0438\u043f\u043e\u0432 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u0442\u0438\u043f \u0443\u0437\u043b\u0430\u00bb \u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u043c \u0443\u0437\u043b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u0439 \u0442\u0438\u043f\u044b.", "Text_src": "In addition to setting the default child type, the child node types that are available to be set can be limited. There is a pull-down list of child type limits in the \"Type Config\" tab of the configuration dialog if the advanced functions are shown. Only checked types will show up in the type lists when using the \"Data > Set Node Type\" command on a child node." }, "format": "HEAD_PARA", "uid": "aa6f6ca4bb0711e7bbf43417ebd53aeb" }, { "children": [ "90dbc4e4334b11e892d0d66a6ab671cb", "299ba9e4334a11e881a6d66a6ab671cb", "e46163b4334b11e88512d66a6ab671cb", "a7fa190c334911e88d18d66a6ab671cb", "f817e5b6334a11e89349d66a6ab671cb", "7716c96e334a11e896bfd66a6ab671cb", "46fc4054334b11e89299d66a6ab671cb", "9a8a1400334c11e89838d66a6ab671cb", "145bd91a334c11e896b1d66a6ab671cb", "edd50b80334c11e8b5f5d66a6ab671cb", "b7ec7052334a11e88325d66a6ab671cb" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "b16866da333f11e88adbd66a6ab671cb" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u044c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 [\u043f\u0443\u0442\u0438]", "Name_src": "Breadcrumb view", "Text": "\u0412 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438, \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0449\u0435\u0439\u0441\u044f \u0441\u0432\u0435\u0440\u0445\u0443 [\u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043f\u0440\u0430\u0432\u0430] \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 [\u0438\u043d\u0430\u0447\u0435 \u0438\u043c\u0435\u043d\u0430] \u043f\u0440\u0435\u0434\u043a\u043e\u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430; \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c \u043c\u043e\u0436\u043d\u043e \u0449\u0435\u043b\u043a\u043d\u0443\u0442\u044c \u043c\u044b\u0448\u044c\u044e \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0438\u0445 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435.", "Text_src": "An upper breadcrumb view shows titles of the selected node's ancestors; the titles can be clicked to select them in the tree." }, "format": "BULLETS", "uid": "b1b5d434b32911e780fd3417ebd53aeb" }, { "children": [], "data": { "Name": "Live tree HTML export", "Text": "A new HTML export uses Javascript and CSS to create a live tree view. Nodes in the tree can be expanded and collapsed, and a separate pane shows the output for all descendants of the selected node. One form of this export creates separate files that are linked to the existing TreeLine file. These files are intended for use on a web server (browser security usually prevents local access). Only the TreeLine file needs to be replaced to update the data (re-export is not required). The second form creates a single file (with embedded data) that can be accessed from a local web browser." }, "format": "BULLETS", "uid": "b1cd1f82334111e8b89ad66a6ab671cb" }, { "children": [], "data": { "Name": "Search and replace", "Text": "Added support for finding and replacing empty data fields using the search and replace command." }, "format": "BULLETS", "uid": "b398d8ee482211e989f27054d2175f18" }, { "children": [ "b5fe6aa030e111ebbc097054d2175f18" ], "data": { "Name": "November 27, 2020 - Release 3.1.4 (stable release)" }, "format": "HEADINGS", "uid": "b5fe698830e111ebbc097054d2175f18" }, { "children": [ "b5fe74c830e111ebbc097054d2175f18", "b5fe6f0030e111ebbc097054d2175f18", "b5fe737e30e111ebbc097054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "b5fe6aa030e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Window closing error", "Text": "Avoid an error message when a window is closed with the focus on a dialog box." }, "format": "BULLETS", "uid": "b5fe6f0030e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Math field root reference", "Text": "Fix a problem recalculating root references in field equations." }, "format": "BULLETS", "uid": "b5fe737e30e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Python 3.9 compatible", "Text": "Fix an incompatibility with the new Python 3.9 version under Linux or running from source." }, "format": "BULLETS", "uid": "b5fe74c830e111ebbc097054d2175f18" }, { "children": [], "data": { "Name": "Font dialog bug", "Text": "Avoid problems with empty parameters in the font dialogs." }, "format": "BULLETS", "uid": "b6a4a6bddc8911ea8612ac675dac20af" }, { "children": [], "data": { "Name": "Output table spacing", "Text": "Fixed minor spacing issues for tables shown in output views and HTML exports." }, "format": "BULLETS", "uid": "b7ec7052334a11e88325d66a6ab671cb" }, { "children": [], "data": { "Name": "\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u041f\u043e\u043b\u044f", "Name_src": "Math Fields", "Text": "\u0411\u043e\u043b\u0435\u0435 \u0441\u043b\u043e\u0436\u043d\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0432\u043e\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0443\u0447\u0435\u043d \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445, \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0438 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0441\u043c. \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0422\u0438\u043f.", "Text_src": "For more complex output formatting, the math field can be used to combine other fields using various mathematical, relational and string operators. See the Math Type section for details." }, "format": "HEAD_PARA", "uid": "bbbf735ac24711e8b560d66a6ab671cb" }, { "children": [], "data": { "Name": "Cut last node", "Text": "Fix an error caused by attempting to use the Edit > Cut command when there is only one node." }, "format": "BULLETS", "uid": "bdc8628ec2bd11e889e57054d2175f18" }, { "children": [], "data": { "Name": "MacPorts reference", "Text": "References to a macOS port on MacPorts were added to the System Requirements and Installation documentation." }, "format": "BULLETS", "uid": "c1f8dca5dc9511ea8f76ac675dac20af" }, { "children": [], "data": { "Name": "Data editor hover", "Text": "By default, the edit boxes in the data edit view now activate when the mouse hovers over them. This eliminates the need to click to activate them. This feature can be disabled in general options if desired." }, "format": "BULLETS", "uid": "cd28e024bb0211e79c553417ebd53aeb" }, { "children": [], "data": { "Name": "Unlimited data editor height option", "Text": "Add a general option to extend the height of data editors with long text content. The default setting (limit the height to the window size) is unchanged. The new option uses the view scroll bars to access the full text length." }, "format": "BULLETS", "uid": "cef1d9fee5de11e998dea44cc8e97404" }, { "children": [], "data": { "Name": "Math field recalculation", "Text": "Perform a more complete recalculation of math fields after certain operations." }, "format": "BULLETS", "uid": "cf9c139fdc8e11ea8261ac675dac20af" }, { "children": [], "data": { "Name": "TreeLine 2 import / export", "Text": "Import and export filters are provided for older TreeLine version 2.x and 1.x files. The older files can be opened using the standard \"File > Open\" command." }, "format": "BULLETS", "uid": "d1d8e56eba4011e784ab3417ebd53aeb" }, { "children": [], "data": { "Name": "\u041f\u043e\u0440\u0442\u044b \u043d\u0430 MacOs", "Name_src": "MacPorts", "Text": "\u041f\u043e\u0440\u0442 \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u0439 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 MacPorts. ", "Text_src": "There is a third-party port available on MacPorts." }, "format": "BULLETS", "uid": "d8a76c1fdc9411eaab2dac675dac20af" }, { "children": [], "data": { "Name": "Enable add child", "Text": "Make the Add Child command available after filtering has ended." }, "format": "BULLETS", "uid": "d9119485dc8711ea92dcac675dac20af" }, { "children": [ "ff3f7c98481e11e989f27054d2175f18", "db25ce66481e11e989f27054d2175f18" ], "data": { "Name": "March 17, 2019 - Release 3.1.1 (stable release)" }, "format": "HEADINGS", "uid": "db25cd62481e11e989f27054d2175f18" }, { "children": [ "e3690592481f11e989f27054d2175f18", "84b24010482211e989f27054d2175f18", "db25cf60481e11e989f27054d2175f18", "95d970aa481f11e989f27054d2175f18", "25ab9320482011e989f27054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "db25ce66481e11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Math equation with copied type", "Text": "Fix problems defining a math field equation on a recently copied data type." }, "format": "BULLETS", "uid": "db25cf60481e11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Sort root nodes", "Text": "The Sort command now properly sorts multiple root nodes when sorting the entire tree." }, "format": "BULLETS", "uid": "dc700fb4c24211e8b88dd66a6ab671cb" }, { "children": [], "data": { "Name": "Customize colors", "Text": "Add a more flexible tool for customizing GUI colors." }, "format": "BULLETS", "uid": "dca5b84fdc8a11eab098ac675dac20af" }, { "children": [], "data": { "Name": "Multi-level CSV import / export", "Text": "New forms of CSV table text imports and exports can work with multiple levels of child nodes, preserving the tree structure. The first column of the table includes a level number that is incremented for child relationships." }, "format": "BULLETS", "uid": "dd22e382334111e894e6d66a6ab671cb" }, { "children": [], "data": { "Name": "Dark mode printing", "Text": "Fix printing problems when using the dark theme." }, "format": "BULLETS", "uid": "e3690592481f11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Error after empty filter", "Text": "Avoid problems showing the tree view after closing a filter command that found no matches." }, "format": "BULLETS", "uid": "e46163b4334b11e88512d66a6ab671cb" }, { "children": [], "data": { "Name": "Deletion errors", "Text": "Several errors occurring when deleting or removing nodes have been fixed. These include problems when the mouse is pre-highlighting descendant nodes and when nodes to be deleted are selected in a separate window." }, "format": "BULLETS", "uid": "e4fc680a786911e899d3a44cc8e97404" }, { "children": [], "data": { "Name": "Breadcrumb view", "Text": "A new breadcrumb view pane above the other panes shows a sequence of ancestor titles for a selected node. The ancestors can be clicked to select them. For cloned nodes, multiple lines provide links to each instance's ancestor sequence." }, "format": "BULLETS", "uid": "e6ad9f6eba4311e796bd3417ebd53aeb" }, { "children": [], "data": { "Name": "Windows binary", "Text": "The Windows binary is now built using updated libraries (Qt 5.11 and PyQt 5.11)." }, "format": "BULLETS", "uid": "e7776f4da14511e88aefa44cc8e97404" }, { "children": [], "data": { "Name": "Major rewrite", "Text": "This is the first stable release of a major TreeLine rewrite. It includes all of the new features shown below in the 2.1.x and 2.9.x development series." }, "format": "BULLETS", "uid": "e8e10d32a14311e8ab90a44cc8e97404" }, { "children": [ "e8e10d34a14311e899cca44cc8e97404", "e8e10d38a14311e8a0c3a44cc8e97404", "e8e10d37a14311e8b0b3a44cc8e97404" ], "data": { "Name": "August 19, 2018 - Release 3.0.0 (new stable release)" }, "format": "HEADINGS", "uid": "e8e10d33a14311e88e24a44cc8e97404" }, { "children": [ "e8e10d32a14311e8ab90a44cc8e97404", "e8e10d35a14311e8aca9a44cc8e97404", "e8e10d36a14311e8b832a44cc8e97404" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "e8e10d34a14311e899cca44cc8e97404" }, { "children": [], "data": { "Name": "Compatibility", "Text": "TreeLine files now use a JSON format in place of the old XML format. This provides more flexibility for structuring new features like cloned nodes and multiple root nodes. A new file extension (\".trln) helps to distinguish files with the new format. Import and export filters are provided for older TreeLine version 2.x and 1.x files. The older files can be opened using the standard \"File > Open\" command." }, "format": "BULLETS", "uid": "e8e10d35a14311e8aca9a44cc8e97404" }, { "children": [], "data": { "Name": "Translations", "Text": "A GUI translations is available in German. All other translations are out of date and have not been included. Volunteers are needed to update translations in several languages." }, "format": "BULLETS", "uid": "e8e10d36a14311e8b832a44cc8e97404" }, { "children": [ "e7776f4da14511e88aefa44cc8e97404" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "e8e10d37a14311e8b0b3a44cc8e97404" }, { "children": [ "e8e10d3ca14311e8b71da44cc8e97404" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "e8e10d38a14311e8a0c3a44cc8e97404" }, { "children": [], "data": { "Name": "Default font", "Text": "The default font for the application can now be set in Tools > Customize Fonts. This is useful for enlarging fonts on some systems with high screen resolutions. Options still exist to individually specify tree view, output view and editor fonts." }, "format": "BULLETS", "uid": "e8e10d3ca14311e8b71da44cc8e97404" }, { "children": [], "data": { "Name": "Add modified flag", "Text": "Add an asterisk after the file name in the title bar if a file has been modified." }, "format": "BULLETS", "uid": "ea0c9b24e79911e98abe7054d2175f18" }, { "children": [], "data": { "Name": "Category command disable", "Text": "Avoid problems running data category-based commands on selections without any child nodes." }, "format": "BULLETS", "uid": "edd50b80334c11e8b5f5d66a6ab671cb" }, { "children": [], "data": { "Name": "Initial field values", "Text": "Fixed errors occurring when field types are changed after initial default values have been set." }, "format": "BULLETS", "uid": "f011a5d8786911e8ace3a44cc8e97404" }, { "children": [], "data": { "Name": "\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b", "Name_src": "Cloned nodes", "Text": "\u0423\u0437\u043b\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0443\u0431\u043b\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043f\u0443\u0442\u0435\u043c \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 [\u043f\u0443\u0442\u0435\u0439] \u0441\u0432\u0435\u0440\u0445\u0443 \u043a\u0430\u043a \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0443\u0437\u043b\u044b, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u044f.", "Text_src": "Nodes that are duplicated by cloning show up as separate clickable paths in the upper breadcrumb view." }, "format": "BULLETS", "uid": "f08b97be792b11e88588a44cc8e97404" }, { "children": [ "f16f7f70a25a11e7b7c67054d2175f18", "f16f87b8a25a11e7b7c67054d2175f18", "f16fbef4a25a11e7b7c67054d2175f18", "f16fc7aaa25a11e7b7c67054d2175f18", "f16fd236a25a11e7b7c67054d2175f18", "f16fe6fea25a11e7b7c67054d2175f18", "f1703d8ea25a11e7b7c67054d2175f18", "f1713464a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f TreeLine", "Name_src": "TreeLine Documentation" }, "format": "HEADINGS", "uid": "f16f7d90a25a11e7b7c67054d2175f18" }, { "children": [ "f16f82aea25a11e7b7c67054d2175f18", "f16f8498a25a11e7b7c67054d2175f18", "f16f85b0a25a11e7b7c67054d2175f18", "f16f86aaa25a11e7b7c67054d2175f18", "6e4dd051678a11eb8f00001fd026534b" ], "data": { "Name": "\u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435", "Name_src": "Introduction" }, "format": "HEADINGS", "uid": "f16f7f70a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0412\u0435\u0440\u0441\u0438\u044f", "Name_src": "Version", "Text": "\u0412 \u044d\u0442\u043e\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u044b\u0439 \u0440\u0435\u043b\u0438\u0437 TreeLine, \u0432\u0435\u0440\u0441\u0438\u0438 3.2.1. \u043e\u0442 27 \u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044f 2025 \u0433., \u0430\u0432\u0442\u043e\u0440 \u0414\u0443\u0433 \u0411\u0435\u043b\u043b (Doug Bell).", "Text_src": "This document covers TreeLine, Version 3.2.0, a stable release, dated August 30, 2025 by Doug Bell." }, "format": "PARAGRAPH", "uid": "f16f82aea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u0447\u0435\u043c\u0443 TreeLine?", "Name_src": "Why TreeLine?", "Text": "\u0423 \u0432\u0430\u0441 \u043c\u0430\u0441\u0441\u0430 \u0441\u0442\u0438\u043a\u0435\u0440\u043e\u0432 \u0441 \u0437\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0439 \u043d\u0430 \u043d\u0438\u0445 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e\u0439 \u043f\u043e\u043b\u0435\u0437\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439, \u0440\u0430\u0437\u0431\u0440\u043e\u0441\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u0432\u0441\u044e\u0434\u0443? \u0418\u043b\u0438 \u043a\u0443\u0447\u0438 \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u043a\u043d\u0438\u0433, \u0444\u0438\u043b\u044c\u043c\u043e\u0432, \u0441\u0441\u044b\u043b\u043e\u043a, \u0443\u0447\u0435\u0442\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439 \u0432\u0435\u0431-\u0441\u0430\u0439\u0442\u043e\u0432, \u043b\u0438\u0447\u043d\u044b\u0445 \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432 \u0438\u043b\u0438 \u0434\u0435\u043b? \u041c\u043e\u0436\u0435\u0442\u0435 \u043b\u0438 \u0432\u044b \u043d\u0430\u0439\u0442\u0438 \u0438\u0445, \u043a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u0432\u0430\u043c \u043d\u0443\u0436\u043d\u044b? \u0427\u0442\u043e \u0436, \u043c\u043d\u0435 \u0447\u0430\u0441\u0442\u043e \u043d\u0435 \u0443\u0434\u0430\u0432\u0430\u043b\u043e\u0441\u044c. \u0418\u0442\u0430\u043a, \u044d\u0442\u043e \u043c\u043e\u0439 \u043e\u0442\u0432\u0435\u0442.", "Text_src": "Do you have lots of sticky notes lying around with various useful information jotted down? Or many lists of books, movies, links, website logins, personal contacts, or things to do? Can you find them when you need them? Well, I often couldn't. So here's my answer." }, "format": "PARAGRAPH", "uid": "f16f8498a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u0432\u043c\u0435\u0441\u0442\u043e \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445", "Name_src": "Outliner vs. database", "Text": "TreeLine \u2014 \u044d\u0442\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0438 \u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0449\u0438\u043a \u0438 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f \u0431\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u043d\u0435\u043c \u043c\u043e\u0436\u0435\u0442 \u0445\u0440\u0430\u043d\u0438\u0442\u044c\u0441\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043b\u044e\u0431\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f. \u0414\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u0440\u044f\u0434\u043e\u043a. \u0410 \u043a\u0430\u0436\u0434\u044b\u0439 \u0443\u0437\u0435\u043b \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0439, \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0449\u0438\u0445 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0441\u0432\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0432\u043e\u0434\u0430, \u0430 \u0432\u044b\u0432\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435, \u0440\u0430\u0441\u043f\u0435\u0447\u0430\u0442\u0430\u043d \u0438\u043b\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d \u0432 HTML \u0438\u043b\u0438 \u0442\u0435\u043a\u0441\u0442.", "Text_src": "TreeLine is both an outliner and a small database. It stores almost any kind of information. A tree structure makes it easy to keep things organized. And each node in the tree can contain several fields, forming a database. The output format for each node can be defined, and the output can be shown on the screen, printed, or exported to HTML or text." }, "format": "PARAGRAPH", "uid": "f16f85b0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041b\u0438\u0446\u0435\u043d\u0437\u0438\u044f", "Name_src": "License", "Text": "\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u044f \u043d\u0435 \u0438\u0437 \u0431\u0438\u0437\u043d\u0435\u0441\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0433\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f, \u044f \u0434\u0435\u043b\u0430\u044e \u044d\u0442\u0443 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0443 \u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0439 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f, \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0438 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438, \u0434\u043e \u0442\u0435\u0445 \u043f\u043e\u0440 \u043f\u043e\u043a\u0430 \u043e\u043d\u0430 \u043d\u0435 \u0441\u0442\u0430\u043d\u0435\u0442 \u0447\u0430\u0441\u0442\u043d\u043e\u0439 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e. TreeLine \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u044b\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u044b\u043c \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435\u043c; \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0442\u044c \u0438 / \u0438\u043b\u0438 \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0435\u0433\u043e \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0438 \u0441 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c\u0438 \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u041e\u0431\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u041b\u0438\u0446\u0435\u043d\u0437\u0438\u0438 GNU, \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u043d\u043d\u043e\u0439 Free Software Foundation; \u043b\u0438\u0431\u043e \u0412\u0435\u0440\u0441\u0438\u0438 2 \u044d\u0442\u043e\u0439 \u041b\u0438\u0446\u0435\u043d\u0437\u0438\u0438, \u043b\u0438\u0431\u043e (\u043f\u043e \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u044b\u0431\u043e\u0440\u0443) \u043b\u044e\u0431\u0443\u044e \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0437\u0434\u043d\u0435\u0439 \u0432\u0435\u0440\u0441\u0438\u0438. \u042d\u0442\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u043d\u0430\u0434\u0435\u0436\u0434\u0435, \u0447\u0442\u043e \u043e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u0435\u0437\u043d\u0430, \u043d\u043e \u0411\u0415\u0417 \u041a\u0410\u041a\u0418\u0425-\u041b\u0418\u0411\u041e \u0413\u0410\u0420\u0410\u041d\u0422\u0418\u0419. \u0417\u0430 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u043e\u0431\u0440\u0430\u0449\u0430\u0439\u0442\u0435\u0441\u044c \u043a \u0444\u0430\u0439\u043b\u0443 LICENSE, \u043f\u0440\u0438\u043b\u0430\u0433\u0430\u0435\u043c\u043e\u043c \u043a \u044d\u0442\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0435.", "Text_src": "Since I'm not in the software business, I'm making this program free for anyone to use, distribute and modify, as long as it stays non-proprietary. TreeLine is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either Version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. See the LICENSE file provided with this program for more information." }, "format": "PARAGRAPH", "uid": "f16f86aaa25a11e7b7c67054d2175f18" }, { "children": [ "f16f8aeca25a11e7b7c67054d2175f18", "f16f9654a25a11e7b7c67054d2175f18", "f16f9c44a25a11e7b7c67054d2175f18", "f16fa040a25a11e7b7c67054d2175f18", "f16fa31aa25a11e7b7c67054d2175f18", "f16fa806a25a11e7b7c67054d2175f18", "f16fadf6a25a11e7b7c67054d2175f18", "f16fb1dea25a11e7b7c67054d2175f18", "f16fb90ea25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438", "Name_src": "Features" }, "format": "HEADINGS", "uid": "f16f87b8a25a11e7b7c67054d2175f18" }, { "children": [ "f16f9050a25a11e7b7c67054d2175f18", "f16f921ca25a11e7b7c67054d2175f18", "f16f932aa25a11e7b7c67054d2175f18", "f16f9424a25a11e7b7c67054d2175f18", "f16f9550a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041e\u0431\u0449\u0438\u0435", "Name_src": "General" }, "format": "BULLET_HEADING", "uid": "f16f8aeca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0425\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438", "Name_src": "Store information", "Text": "\u0425\u0440\u0430\u043d\u0438\u0442 \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043b\u044e\u0431\u043e\u0439 \u0442\u0438\u043f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0435\u043a\u0441\u0442, \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442, HTML, \u0447\u0438\u0441\u043b\u0430, \u0434\u0430\u0442\u044b, \u0432\u0440\u0435\u043c\u044f, \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, URL-\u0430\u0434\u0440\u0435\u0441\u0430 \u0438 \u0442.\u0434.", "Text_src": "Stores almost any type of information, including plain text, rich text, HTML, numbers, dates, times, booleans, URLs, etc." }, "format": "BULLETS", "uid": "f16f9050a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0414\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430", "Name_src": "Tree structure", "Text": "\u0414\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u043e\u0440\u044f\u0434\u043a\u0435.", "Text_src": "The tree structure helps keep things organized." }, "format": "BULLETS", "uid": "f16f921ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u043b\u044f", "Name_src": "Fields", "Text": "\u041a\u0430\u0436\u0434\u044b\u0439 \u0443\u0437\u0435\u043b \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. ", "Text_src": "Each node can have several fields that form a mini-database." }, "format": "BULLETS", "uid": "f16f932aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f\u044b \u0443\u0437\u043b\u043e\u0432", "Name_src": "Node types", "Text": "\u0412 \u043e\u0434\u043d\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0438\u043f\u043e\u0432 \u0443\u0437\u043b\u043e\u0432 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043d\u0430\u0431\u043e\u0440\u0430\u043c\u0438 \u043f\u043e\u043b\u0435\u0439.", "Text_src": "Several node types, with different sets of fields, can be included in one file." }, "format": "BULLETS", "uid": "f16f9424a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0424\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0432\u043e\u0434\u0430", "Name_src": "Output format", "Text": "\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0443\u0437\u043b\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0432\u043e\u0434\u0430, \u0432\u043a\u043b\u044e\u0447\u0430\u044e\u0449\u0438\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043f\u043e\u043b\u0435\u0439, \u0441\u0442\u0440\u043e\u043a \u0432\u044b\u0432\u043e\u0434\u0430, \u0438\u0445 \u043e\u0444\u043e\u0440\u043c\u043b\u0435\u043d\u0438\u0435 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0437\u043d\u0430\u0447\u043a\u043e\u0432 \u0434\u043b\u044f \u0434\u0435\u0440\u0435\u0432\u0430.", "Text_src": "The node format, including fields, output lines, formatting and tree-view icon, can be defined for each node type." }, "format": "BULLETS", "uid": "f16f9550a25a11e7b7c67054d2175f18" }, { "children": [ "f16f9744a25a11e7b7c67054d2175f18", "f16f9834a25a11e7b7c67054d2175f18", "f16f992ea25a11e7b7c67054d2175f18", "f16f9a32a25a11e7b7c67054d2175f18", "f16f9b36a25a11e7b7c67054d2175f18", "b1b5d434b32911e780fd3417ebd53aeb" ], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u0438", "Name_src": "Views" }, "format": "BULLET_HEADING", "uid": "f16f9654a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u044c \u0434\u0435\u0440\u0435\u0432\u0430", "Name_src": "Tree view", "Text": "\u0412 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043b\u0435\u0432\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043e\u0442\u0441\u0442\u0443\u043f\u043e\u0432, \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0438\u0439\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 [\u0443\u0437\u043b\u043e\u0432].", "Text_src": "The left-hand view shows an indented, expandable list of titles" }, "format": "BULLETS", "uid": "f16f9744a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u0438 \u0441\u043f\u0440\u0430\u0432\u0430", "Name_src": "Right-hand views", "Text": "\u0424\u043e\u0440\u043c\u0430 \u0441\u043f\u0440\u0430\u0432\u0430 \u043c\u043e\u0436\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u043e\u0434\u043d\u0443 \u0438\u0437 \u0442\u0440\u0435\u0445 \u043f\u0430\u043d\u0435\u043b\u0435\u0439 \u2014 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432\u044b\u0432\u043e\u0434\u0430, \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432 \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0443\u0437\u043b\u043e\u0432.", "Text_src": "The right-hand view can show one of three views - for showing output, editing node data and editing node titles." }, "format": "BULLETS", "uid": "f16f9834a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u043a\u0430\u0437 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432", "Name_src": "Show parent and children", "Text": "\u041f\u0430\u043d\u0435\u043b\u044c \u0441\u043f\u0440\u0430\u0432\u0430 \u043e\u0431\u044b\u0447\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0430 \u043d\u0430 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u043f\u043e\u043a\u0430\u0437\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u0438 \u0435\u0433\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432.", "Text_src": "The right-hand view is normally split to show data from the parent node and its children." }, "format": "BULLETS", "uid": "f16f992ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u043a\u0430\u0437 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430", "Name_src": "Show multiple selection", "Text": "\u0415\u0441\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043b\u043e\u0432, \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043f\u0440\u0430\u0432\u0430 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u044b \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435\u0441\u044f \u0432 \u043d\u0438\u0445.", "Text_src": "If multiple nodes are selected, the right-hand view shows all of their data." }, "format": "BULLETS", "uid": "f16f9a32a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u043a\u0430\u0437 \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432", "Name_src": "Show descendant output", "Text": "\u041f\u0430\u043d\u0435\u043b\u044c \u0432\u044b\u0432\u043e\u0434\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0434\u043b\u044f \u043f\u043e\u043a\u0430\u0437\u0430 \u0432\u044b\u0432\u043e\u0434\u0430 \u0432\u0441\u0435\u0445 \u0443\u0437\u043b\u043e\u0432-\u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432 \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0442\u0441\u0442\u0443\u043f\u043e\u0432.", "Text_src": "The output view can be set to show indented output from all descendant nodes." }, "format": "BULLETS", "uid": "f16f9b36a25a11e7b7c67054d2175f18" }, { "children": [ "f16f9d2aa25a11e7b7c67054d2175f18", "f16f9e2ea25a11e7b7c67054d2175f18", "f16f9f3ca25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u0443\u0442\u0438", "Name_src": "Navigation" }, "format": "BULLET_HEADING", "uid": "f16f9c44a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0438\u0441\u043a\u0430", "Name_src": "Find commands", "Text": "\u041f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434 \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u0430 \u043f\u043e\u0438\u0441\u043a \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u043b\u0438 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u043f\u043e \u0431\u043e\u043b\u0435\u0435 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c.", "Text_src": "Find commands can search node data for text matches or for more specific rules." }, "format": "BULLETS", "uid": "f16f9d2aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0424\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f", "Name_src": "Filtering", "Text": "\u041f\u0440\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0432 \u043b\u0435\u0432\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0432\u043f\u0430\u0432\u0448\u0438\u0435 \u0441 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u043c\u0438 [\u0444\u0438\u043b\u044c\u0442\u0440\u0430] \u0443\u0437\u043b\u044b. ", "Text_src": "Filtering commands show only matching nodes in a flat left-hand view." }, "format": "BULLETS", "uid": "f16f9e2ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0432\u044b\u0431\u043e\u0440\u0430", "Name_src": "Toggle selections", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0432\u044b\u0431\u043e\u0440, \u0447\u0442\u043e\u0431\u044b \u0431\u044b\u0441\u0442\u0440\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u0447\u0430\u0441\u0442\u044f\u043c\u0438 \u0434\u0435\u0440\u0435\u0432\u0430.", "Text_src": "Previous and next selection commands toggle selections to quickly move between parts of the tree." }, "format": "BULLETS", "uid": "f16f9f3ca25a11e7b7c67054d2175f18" }, { "children": [ "f16fa130a25a11e7b7c67054d2175f18", "5c1d58ac792a11e8b78ca44cc8e97404", "f16fa220a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", "Name_src": "Formatting" }, "format": "BULLET_HEADING", "uid": "f16fa040a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u043a\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438", "Name_src": "Configuration dialog", "Text": "\u0412 \u043e\u043a\u043d\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u043a\u043b\u0430\u0434\u043e\u043a \u0434\u043b\u044f \u043b\u0435\u0433\u043a\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0432\u0441\u0435\u0445 \u0442\u0438\u043f\u043e\u0432, \u043f\u043e\u043b\u0435\u0439 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432\u044b\u0432\u043e\u0434\u0430.", "Text_src": "The dialog for data type configuration has several tabs to easily set all type, field and output parameters." }, "format": "BULLETS", "uid": "f16fa130a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041a\u043e\u043f\u0438\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0430", "Name_src": "Format copies", "Text": "\u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 TreeLine.", "Text_src": "Formatting information can be copied from another TreeLine file." }, "format": "BULLETS", "uid": "f16fa220a25a11e7b7c67054d2175f18" }, { "children": [ "f16fa40aa25a11e7b7c67054d2175f18", "f16fa504a25a11e7b7c67054d2175f18", "f16fa5fea25a11e7b7c67054d2175f18", "f16fa70ca25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0424\u0430\u0439\u043b\u043e\u0432", "Name_src": "File Handling" }, "format": "BULLET_HEADING", "uid": "f16fa31aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u0442\u043c\u0435\u043d\u0430/\u041f\u043e\u0432\u0442\u043e\u0440", "Name_src": "Undo/redo", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u044b \u043e\u0442\u043c\u0435\u043d\u044b \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f.", "Text_src": "Undo and redo commands are available for all modifying operations." }, "format": "BULLETS", "uid": "f16fa40aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0424\u043e\u0440\u043c\u0430\u0442\u044b \u0444\u0430\u0439\u043b\u043e\u0432", "Name_src": "File formats", "Text": "\u0424\u0430\u0439\u043b\u044b TreeLine \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442 JSON \u0441 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0441\u0436\u0430\u0442\u0438\u044f \u0438\u043b\u0438 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432.", "Text_src": "TreeLine files use a JSON format, with options for automatically compressing or encrypting the files." }, "format": "BULLETS", "uid": "f16fa504a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0428\u0430\u0431\u043b\u043e\u043d\u044b \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432", "Name_src": "Document templates", "Text": "\u0428\u0430\u0431\u043b\u043e\u043d\u044b \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u0437\u0430\u0434\u0430\u0447.", "Text_src": "Document templates for new files are preformatted to cover basic needs." }, "format": "BULLETS", "uid": "f16fa5fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0435\u0447\u0430\u0442\u044c", "Name_src": "Printing", "Text": "\u041e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0440\u0430\u0441\u043f\u0435\u0447\u0430\u0442\u0430\u043d\u044b, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0438 \u0438\u0437 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445/\u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432, \u0432\u0435\u0440\u0445\u043d\u0438\u0435 \u0438 \u043d\u0438\u0436\u043d\u0438\u0435 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b\u044b.", "Text_src": "The formatted output can be printed with parent/child lines, headers and footers." }, "format": "BULLETS", "uid": "f16fa70ca25a11e7b7c67054d2175f18" }, { "children": [ "f16fa8f6a25a11e7b7c67054d2175f18", "31304c06792b11e888cfa44cc8e97404", "f16fa9f0a25a11e7b7c67054d2175f18", "9bd80f34b32b11e7be613417ebd53aeb", "f16faaf4a25a11e7b7c67054d2175f18", "f16fabf8a25a11e7b7c67054d2175f18", "f16facf2a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0444\u0430\u0439\u043b\u043e\u0432", "Name_src": "File Import and Export" }, "format": "BULLET_HEADING", "uid": "f16fa806a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 HTML", "Name_src": "HTML export", "Text": "\u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b HTML, \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0435 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0434\u043d\u043e\u0433\u043e \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0441 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u043f\u0430\u043d\u0435\u043b\u044f\u043c\u0438 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438.", "Text_src": "The data can be exported to single or multiple HTML files with optional navigation panes." }, "format": "BULLETS", "uid": "f16fa8f6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442/\u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0442\u0435\u043a\u0441\u0442\u0430", "Name_src": "Text import/export", "Text": "\u041c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0435\u043a\u0441\u0442, \u0442\u0435\u043a\u0441\u0442, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0439 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0439, \u0438 \u0444\u0430\u0439\u043b\u044b \u0442\u0430\u0431\u043b\u0438\u0446 \u0441 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f\u043c\u0438.", "Text_src": "Plain text, tab-indented text and delimited table files can be imported and exported." }, "format": "BULLETS", "uid": "f16fa9f0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442/\u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0437\u0430\u043a\u043b\u0430\u0434\u043e\u043a", "Name_src": "Bookmark import/export", "Text": "\u041c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0444\u0430\u0439\u043b\u044b \u0437\u0430\u043a\u043b\u0430\u0434\u043e\u043a \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u0445 Mozilla \u0438 XBEL.", "Text_src": "Mozilla and XBEL format bookmark files can be imported and exported." }, "format": "BULLETS", "uid": "f16faaf4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442/\u044d\u043a\u0441\u043f\u043e\u0440\u0442 XML \u043e\u0431\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430", "Name_src": "Generic XML import/export", "Text": "\u041c\u043e\u0436\u043d\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b XML \u043e\u0431\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430, \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c TreeLine \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 XML.", "Text_src": "Generic XML files can be imported and exported, allowing TreeLine to function as a crude XML editor." }, "format": "BULLETS", "uid": "f16fabf8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442/\u044d\u043a\u0441\u043f\u043e\u0440\u0442 ODF", "Name_src": "ODF import/export", "Text": "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0430 ODF \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 \u0432\u0438\u0434\u0435 \u0438\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440.", "Text_src": "ODF text documents can be imported and exported as outlines." }, "format": "BULLETS", "uid": "f16facf2a25a11e7b7c67054d2175f18" }, { "children": [ "f16faee6a25a11e7b7c67054d2175f18", "f16fafe0a25a11e7b7c67054d2175f18", "f16fb0daa25a11e7b7c67054d2175f18", "f08b97be792b11e88588a44cc8e97404" ], "data": { "Name": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043e\u043a", "Name_src": "Linking" }, "format": "BULLET_HEADING", "uid": "f16fadf6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438", "Name_src": "Internal links", "Text": "\u041f\u043e \u0449\u0435\u043b\u0447\u043a\u0443 \u043d\u0430 \u043f\u043e\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043e\u043a [\u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 Treeline \u0438 \u0444\u0430\u0439\u043b\u0430\u0445, \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438] \u0432\u044b\u0431\u0438\u0440\u0430\u044e\u0442\u0441\u044f \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0435 \u0441 \u043d\u0438\u043c\u0438 \u0443\u0437\u043b\u044b.", "Text_src": "Internal link fields select a linked node when clicked." }, "format": "BULLETS", "uid": "f16faee6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0412\u043d\u0435\u0448\u043d\u0438\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438", "Name_src": "External links", "Text": "\u0412\u043d\u0435\u0448\u043d\u0438\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438 [\u0432 \u0444\u043e\u0440\u043c\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 Treeline \u0438 \u0444\u0430\u0439\u043b\u0430\u0445, \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0449\u0438\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438] \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f URL \u0432 web-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430\u0445.", "Text_src": "External link fields can be used to open URLs in web browsers." }, "format": "BULLETS", "uid": "f16fafe0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0412\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438", "Name_src": "Embedded links", "Text": "\u041a\u0430\u043a \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435, \u0442\u0430\u043a \u0438 \u0432\u043d\u0435\u0448\u043d\u0438\u0435 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044f.", "Text_src": "Both internal and external links can be embedded into text fields." }, "format": "BULLETS", "uid": "f16fb0daa25a11e7b7c67054d2175f18" }, { "children": [ "f16fb2cea25a11e7b7c67054d2175f18", "f16fb3c8a25a11e7b7c67054d2175f18", "f16fb4eaa25a11e7b7c67054d2175f18", "f16fb5e4a25a11e7b7c67054d2175f18", "5f12f768b32c11e7a41a3417ebd53aeb", "f16fb6dea25a11e7b7c67054d2175f18", "f16fb7f6a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438", "Name_src": "Data Manipulation" }, "format": "BULLET_HEADING", "uid": "f16fb1dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430", "Name_src": "Sorting", "Text": "\u0423\u0437\u043b\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443 \u0438\u043b\u0438 \u043f\u043e \u043f\u0440\u0435\u0434\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u043c \u043f\u043e\u043b\u044f\u043c.", "Text_src": "Nodes can be sorted by title or by predefined key fields." }, "format": "BULLETS", "uid": "f16fb2cea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e\u043b\u044f", "Name_src": "Math Fields", "Text": "\u041c\u043e\u0436\u043d\u043e \u043d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442 \u0438\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0443\u0437\u043b\u0430\u0445.", "Text_src": "Math fields can be defined that automatically calculate their contents based on numerical values in other nodes." }, "format": "BULLETS", "uid": "f16fb3c8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044f", "Name_src": "Numbering", "Text": "\u041c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u043f\u043e\u043b\u044f \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438.", "Text_src": "Numbering fields can be defined and automatically updated." }, "format": "BULLETS", "uid": "f16fb4eaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0423\u0441\u043b\u043e\u0432\u043d\u044b\u0435 \u0442\u0438\u043f\u044b", "Name_src": "Conditional types", "Text": "\u0417\u043d\u0430\u0447\u043a\u0438 \u0443\u0437\u043b\u0430 \u0438 \u0444\u043e\u0440\u043c\u0430\u0442 \u0435\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u044b \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0445\u0441\u044f \u0432 \u043d\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445.", "Text_src": "A node's icon and output format can be changed conditionally based on its data." }, "format": "BULLETS", "uid": "f16fb5e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f", "Name_src": "Spell check", "Text": "\u0412 \u043f\u043e\u043b\u044f\u0445 \u0441 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f (\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0432\u043d\u0435\u0448\u043d\u044f\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u2014 \u0441\u043c. \u0420\u0430\u0437\u0434\u0435\u043b \u00ab\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f\u00bb).", "Text_src": "Text data can be spell checked (requires an external program - see the System Requirements section)." }, "format": "BULLETS", "uid": "f16fb6dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445", "Name_src": "Arranging data", "Text": "\u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439 \u0438\u0437 \u043f\u043e\u043b\u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0445.", "Text_src": "Data can be automatically re-arranged using categories from data fields." }, "format": "BULLETS", "uid": "f16fb7f6a25a11e7b7c67054d2175f18" }, { "children": [ "f16fba08a25a11e7b7c67054d2175f18", "f16fbb02a25a11e7b7c67054d2175f18", "f16fbc06a25a11e7b7c67054d2175f18", "f16fbd00a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430", "Name_src": "Customization" }, "format": "BULLET_HEADING", "uid": "f16fb90ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430", "Name_src": "Customization", "Text": "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043a\u0430\u043a \u043e\u0431\u0449\u0438\u0445, \u0442\u0430\u043a \u0438 \u0444\u0430\u0439\u043b\u043e\u0432\u044b\u0445 \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u043e\u0432.", "Text_src": "There are many options for customizing both general and file-based attributes." }, "format": "BULLETS", "uid": "f16fba08a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0413\u043e\u0440\u044f\u0447\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 \u0438 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432", "Name_src": "Shortcuts and toolbars", "Text": "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u044b \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0439 \u043a\u043b\u0430\u0432\u0438\u0448 \u0438 \u043a\u043e\u043c\u0430\u043d\u0434 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.", "Text_src": "There are editors for keyboard shortcuts and toolbar commands." }, "format": "BULLETS", "uid": "f16fbb02a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0428\u0440\u0438\u0444\u0442\u044b", "Name_src": "Fonts", "Text": "\u0428\u0440\u0438\u0444\u0442\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0449\u0438\u0435\u0441\u044f \u0432 \u0433\u0440\u0430\u0444\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f, \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430\u0445 \u0438 \u0444\u043e\u0440\u043c\u0430\u0445 \u0432\u044b\u0432\u043e\u0434\u0430, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u044b.", "Text_src": "Fonts used in the GUI, editors and output views can be customized." }, "format": "BULLETS", "uid": "f16fbc06a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u042f\u0437\u044b\u043a\u0438", "Name_src": "Languages", "Text": "\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 \u0443\u043f\u0440\u043e\u0449\u0435\u043d\u043d\u043e\u043c \u043a\u0438\u0442\u0430\u0439\u0441\u043a\u043e\u043c, \u0430\u043d\u0433\u043b\u0438\u0439\u0441\u043a\u043e\u043c, \u043d\u0435\u043c\u0435\u0446\u043a\u043e\u043c, \u0440\u0443\u0441\u0441\u043a\u043e\u043c \u0438 \u0438\u0441\u043f\u0430\u043d\u0441\u043a\u043e\u043c \u044f\u0437\u044b\u043a\u0430\u0445. \u041f\u0435\u0440\u0435\u0432\u043e\u0434 \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u044f\u0437\u044b\u043a\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c.", "Text_src": "The user interface is available in simplified Chinese, English, German and Spanish. Translations into other languages are TBD." }, "format": "BULLETS", "uid": "f16fbd00a25a11e7b7c67054d2175f18" }, { "children": [ "f16fbfeea25a11e7b7c67054d2175f18", "f16fc4bca25a11e7b7c67054d2175f18", "460699ebdc9411ea89afac675dac20af" ], "data": { "Name": "\u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0422\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f", "Name_src": "System Requirements" }, "format": "HEADINGS", "uid": "f16fbef4a25a11e7b7c67054d2175f18" }, { "children": [ "f16fc0d4a25a11e7b7c67054d2175f18", "f16fc1cea25a11e7b7c67054d2175f18", "f16fc2c8a25a11e7b7c67054d2175f18", "f16fc3c2a25a11e7b7c67054d2175f18" ], "data": { "Name": "Linux" }, "format": "BULLET_HEADING", "uid": "f16fbfeea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Python", "Name_src": "Python", "Text": "Python (\u0412\u0435\u0440\u0441\u0438\u0438 3.9 \u0438\u043b\u0438 \u0432\u044b\u0448\u0435)", "Text_src": "Python (Version 3.9 or higher)" }, "format": "BULLETS", "uid": "f16fc0d4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Qt", "Name_src": "Qt", "Text": "QT (\u0412\u0435\u0440\u0441\u0438\u0438 6.4 \u0438\u043b\u0438 \u0432\u044b\u0448\u0435)", "Text_src": "QT (Version 6.4 or higher)" }, "format": "BULLETS", "uid": "f16fc1cea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "PyQt", "Name_src": "PyQt", "Text": "PyQt (\u0412\u0435\u0440\u0441\u0438\u0438 6.4 \u0438\u043b\u0438 \u0432\u044b\u0448\u0435)", "Text_src": "PyQt (Version 6.4 or higher)" }, "format": "BULLETS", "uid": "f16fc2c8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f", "Name_src": "Spell check", "Text": "\u0415\u0441\u043b\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f aspell, ispell \u0438\u043b\u0438 hunspell.", "Text_src": "If spell checking is desired, either aspell, ispell or hunspell are required" }, "format": "BULLETS", "uid": "f16fc3c2a25a11e7b7c67054d2175f18" }, { "children": [ "f16fc5aca25a11e7b7c67054d2175f18", "f16fc6b0a25a11e7b7c67054d2175f18" ], "data": { "Name": "Windows", "Name_src": "Windows" }, "format": "BULLET_HEADING", "uid": "f16fc4bca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0414\u0432\u043e\u0438\u0447\u043d\u044b\u0439 \u043a\u043e\u0434", "Name_src": "Binary", "Text": "\u0414\u043e\u043b\u0436\u0435\u043d \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435 \u043f\u043e\u0434 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c Windows 10 \u0438\u043b\u0438 11.", "Text_src": "Should run on any computer running Windows 10 or 11." }, "format": "BULLETS", "uid": "f16fc5aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f", "Name_src": "Spell check", "Text": "\u0415\u0441\u043b\u0438 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f aspell, ispell \u0438\u043b\u0438 hunspell.", "Text_src": "If spell checking is desired, an external program is required. Either aspell, ispell or hunspell must be installed." }, "format": "BULLETS", "uid": "f16fc6b0a25a11e7b7c67054d2175f18" }, { "children": [ "f16fc89aa25a11e7b7c67054d2175f18", "f16fcc96a25a11e7b7c67054d2175f18", "611e03ffdc9411ea930eac675dac20af" ], "data": { "Name": "\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430", "Name_src": "Installation" }, "format": "HEADINGS", "uid": "f16fc7aaa25a11e7b7c67054d2175f18" }, { "children": [ "f16fc98aa25a11e7b7c67054d2175f18", "f16fcaa2a25a11e7b7c67054d2175f18", "f16fcb9ca25a11e7b7c67054d2175f18" ], "data": { "Name": "Linux" }, "format": "HEADINGS", "uid": "f16fc89aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0411\u0430\u0437\u043e\u0432\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430", "Name_src": "Basic installation", "Text": "\u0418\u0437\u0432\u043b\u0435\u043a\u0438\u0442\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0438\u0437 tar-\u0444\u0430\u0439\u043b\u0430 treeline, \u0437\u0430\u0442\u0435\u043c \u0432 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b\u0435 \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u0432 \u043a\u0430\u0442\u0430\u043b\u043e\u0433 TreeLine. \u0414\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u0435 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043e\u0442 \u0438\u043c\u0435\u043d\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f root: \"python install.py\".", "Text_src": "Extract the source files from the treeline tar file, then change to the TreeLine directory in a terminal. For a basic installation, simply execute the following command as root: \"python install.py\"." }, "format": "PARAGRAPH", "uid": "f16fc98aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Python 3", "Name_src": "Python 3", "Text": "\u0415\u0441\u043b\u0438 \u0432 \u0432\u0430\u0448\u0435\u043c \u0434\u0438\u0441\u0442\u0440\u0438\u0431\u0443\u0442\u0438\u0432\u0435 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Python 2.x, \u0432\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u00abpython3\u00bb \u043d\u0430 \u00abpython\u00bb \u0432 \u044d\u0442\u0438\u0445 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0445.", "Text_src": "If your distribution defaults to Python 2.x, you may need to substitute \"python3\" for \"python\" in these commands." }, "format": "PARAGRAPH", "uid": "f16fcaa2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438", "Name_src": "Install options", "Text": "\u0427\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0441\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435: \u00abpython install.py -h\u00bb. \u0427\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c TreeLine \u0441 \u0434\u0440\u0443\u0433\u0438\u043c \u043f\u0440\u0435\u0444\u0438\u043a\u0441\u043e\u043c (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e / usr / local), \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435: \u00abpython install.py -p / prefix / path\u00bb. \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0435\u0439, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435: \u00abpython install.py -x\u00bb.", "Text_src": "To see all install options, use: \"python install.py -h\". To install TreeLine with a different prefix (the default is /usr/local), use: \"python install.py -p /prefix/path\". To skip dependency checks, use: \"python install.py -x\"." }, "format": "PARAGRAPH", "uid": "f16fcb9ca25a11e7b7c67054d2175f18" }, { "children": [ "f16fcf3ea25a11e7b7c67054d2175f18", "f16fd042a25a11e7b7c67054d2175f18", "f16fd132a25a11e7b7c67054d2175f18" ], "data": { "Name": "Windows", "Name_src": "Windows" }, "format": "HEADINGS", "uid": "f16fcc96a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0414\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439", "Name_src": "All users", "Text": "\u0427\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0444\u0430\u0439\u043b \u00abTreeLine-x.x.x-install-all.exe\u00bb. \u0422\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f \u043f\u0440\u0430\u0432\u0430 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430.", "Text_src": "To install for all users, execute the \"TreeLine-x.x.x-install-all.exe\" file. Administrator permissions are required." }, "format": "PARAGRAPH", "uid": "f16fcf3ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0414\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f", "Name_src": "Single user", "Text": "\u0427\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043e\u0434\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f (\u043f\u0440\u0430\u0432\u0430 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f) \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0444\u0430\u0439\u043b \u00abTreeLine-x.x.x-install-user.exe\u00bb.", "Text_src": "To install for a single user (administrator rights are not required), execute the \"TreeLine-x.x.x-install-user.exe\" file." }, "format": "PARAGRAPH", "uid": "f16fd042a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u0440\u0442\u0430\u0442\u0438\u0432\u043d\u0430\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430", "Name_src": "Portable install", "Text": "\u0414\u043b\u044f \u043f\u043e\u0440\u0442\u0430\u0442\u0438\u0432\u043d\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0435 \u0444\u0430\u0439\u043b \u00abTreeLine-x.x.x-install-user.exe\u00bb. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043d\u044f\u0442\u044c \u0444\u043b\u0430\u0436\u043e\u043a \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0430\u0441\u0441\u043e\u0446\u0438\u0430\u0446\u0438\u0438 \u0444\u0430\u0439\u043b\u043e\u0432, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u044f\u0440\u043b\u044b\u043a\u043e\u0432 \u0438 \u0434\u0435\u0438\u043d\u0441\u0442\u0430\u043b\u043b\u044f\u0442\u043e\u0440\u0430. \u041a\u043e\u0433\u0434\u0430 TreeLine \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u0441\u044f \u0438 \u0432\u044b\u0434\u0430\u0441\u0442 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0435 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438, \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b.", "Text_src": "For a portable install, execute the \"TreeLine-x.x.x-install-user.exe\" file. The file association, shortcuts and uninstaller tasks should be unchecked. When TreeLine starts and prompts for the config file location, choose the program directory option." }, "format": "PARAGRAPH", "uid": "f16fd132a25a11e7b7c67054d2175f18" }, { "children": [ "f16fd326a25a11e7b7c67054d2175f18", "f16fdccca25a11e7b7c67054d2175f18", "f16fe0b4a25a11e7b7c67054d2175f18", "f16fe3fca25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041e\u0441\u043d\u043e\u0432\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f", "Name_src": "Basic Usage" }, "format": "HEADINGS", "uid": "f16fd236a25a11e7b7c67054d2175f18" }, { "children": [ "f16fd682a25a11e7b7c67054d2175f18", "28f8844ab58711e79d173417ebd53aeb", "f16fd858a25a11e7b7c67054d2175f18", "f16fd9aca25a11e7b7c67054d2175f18", "f16fdabaa25a11e7b7c67054d2175f18", "f16fdbc8a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0424\u043e\u0440\u043c\u044b \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 (Views)", "Name_src": "Views" }, "format": "HEADINGS", "uid": "f16fd326a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u044c \u0414\u0435\u0440\u0435\u0432\u0430 (Tree View)", "Name_src": "Tree View", "Text": "\u0412 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043b\u0435\u0432\u0430 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0435\u0440\u0435\u0432\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0443\u0437\u043b\u043e\u0432. \u0420\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0443\u0437\u043b\u044b \u043c\u043e\u0433\u0443\u0442 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0438 \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u043a\u0430\u0437\u0430 \u0438\u043b\u0438 \u0441\u043a\u0440\u044b\u0442\u0438\u044f \u0438\u0445 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432 \u2014 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0445 \u0441 \u043e\u0442\u0441\u0442\u0443\u043f\u0430\u043c\u0438. \u0429\u0435\u043b\u0447\u043e\u043a \u043f\u043e \u0443\u0436\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u0443\u0437\u043b\u0443 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a. \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u044b\u0435 \u043c\u0435\u043d\u044e, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0449\u0435\u043b\u0447\u043a\u0443 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438 \u043d\u0430 \u0443\u0437\u043b\u0430\u0445.", "Text_src": "The left-hand view shows a tree of node titles. Parent nodes can be opened and closed to display or hide their indented descendant nodes. Clicking on an already selected node allows the title to be edited. Right-click context menus are available for commonly used functions." }, "format": "HEAD_PARA", "uid": "f16fd682a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u0438 \u0421\u043f\u0440\u0430\u0432\u0430 (Right-hand Views)", "Name_src": "Right-hand Views", "Text": "\u041f\u0430\u043d\u0435\u043b\u044c \u0441\u043f\u0440\u0430\u0432\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u043a\u043b\u0430\u0434\u043a\u0438, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u043e\u0434\u043d\u043e \u0438\u0437 \u0442\u0440\u0435\u0445 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0439 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0412\u044b\u0432\u043e\u0434 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb (\"Data Output\") \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442, \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb (\"Data Edit\") \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430, \u0430 \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432\u00bb \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0443\u0437\u043b\u043e\u0432, \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0434\u0435\u0440\u0435\u0432\u0430.\n

    \n\u041a\u043e\u0433\u0434\u0430 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u0432\u044b\u0431\u0440\u0430\u043d \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0443\u0437\u0435\u043b, \u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043f\u0440\u0430\u0432\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u0443\u0437\u043b\u0435 \u043d\u0430 \u0432\u0435\u0440\u0445\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0430\u043d\u0435\u043b\u0438 \u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u0445 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u043d\u0430 \u043d\u0438\u0436\u043d\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0430\u043d\u0435\u043b\u0438. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \"\u0412\u0438\u0434 > \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u041f\u0430\u043d\u0435\u043b\u044c \u0414\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0423\u0437\u043b\u0430\" (\"View > Show Child Pane\") \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432. \u0415\u0441\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0443\u0437\u0435\u043b \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u043e\u0434\u043d\u0430 \u043f\u0430\u043d\u0435\u043b\u044c \u0441 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0435\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u0443\u0437\u043b\u0435.\n

    \n\u041a\u043e\u0433\u0434\u0430 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043b\u043e\u0432 (\u043f\u0440\u0438 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0438 \u043d\u0430\u0436\u0430\u0442\u043e\u0439 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 Shift \u0438\u043b\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 Ctrl), \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043f\u0440\u0430\u0432\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u0430\u0445. \u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043a\u0430\u0436\u0434\u043e\u043c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c \u0443\u0437\u043b\u0435.\n

    \n\u0415\u0441\u043b\u0438 \u0443\u0437\u043b\u044b \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u044b (\u043f\u0440\u0438 \u0449\u0435\u043b\u0447\u043a\u0435 \u043c\u044b\u0448\u044c\u044e \u0432 \u043f\u0443\u0441\u0442\u043e\u0439 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0438\u043b\u0438 \u043f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u043a\u043d\u043e\u043f\u043a\u0438 \u043c\u044b\u0448\u0438 \u0441 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u043d\u0430\u0436\u0430\u0442\u0438\u0435\u043c Ctrl \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u0432\u044b\u0431\u043e\u0440\u0430 \u0443\u0437\u043b\u0430), \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043f\u0440\u0430\u0432\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u0441\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e\u0431 \u0443\u0437\u043b\u0435 \u0432\u0435\u0440\u0445\u043d\u0435\u0433\u043e \u0443\u0440\u043e\u0432\u043d\u044f (\u043a\u043e\u0440\u043d\u0435\u0432\u043e\u043c).", "Text_src": "The right pane is tabbed to show one of three different views of the data. The \"Data Output\" view shows the formatted text, the \"Data Edit\" view shows text edit boxes, and the \"Title List\" view shows an editable list of node titles.<br />
    <br />
    When a parent node is selected in the tree, the right view will default to showing information about the selected node in an upper pane and information about the selected node's children in a lower pane. The \"View &gt; Show Child Pane\" command will toggle the display of the child nodes. If the selected node has no children, the view will show a single pane with information about the selected node only.<br />
    <br />
    When multiple nodes are selected in the tree (by holding down the shift or Ctrl keys while clicking), the right view will not display any child node information. It will instead show information about every selected node.<br />
    <br />
    When no nodes are selected in the tree (by clicking on a blank area or Ctrl clicking to unselect), the right view will show information about the top-level (root) nodes." }, "format": "HEAD_PARA", "uid": "f16fd858a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u044c \u00ab\u0412\u044b\u0432\u043e\u0434 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb (Data Output View)", "Name_src": "Data Output View", "Text": "\u0412\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0412\u044b\u0432\u043e\u0434 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442. \u0412 \u044d\u0442\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u0442\u0435\u043a\u0441\u0442 \u043d\u0435 \u043c\u043e\u0436\u0435\u0442 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f.\n

    \n\u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0412\u0438\u0434 > \u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0412\u044b\u0432\u043e\u0434 \u041f\u043e\u0442\u043e\u043c\u043a\u043e\u0432\u00bb (\"View > Show Output Descendants\") \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u00ab\u0412\u044b\u0432\u043e\u0434 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb (Data Output View) \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0441 \u043e\u0442\u0441\u0442\u0443\u043f\u0430\u043c\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u043a\u0430\u0436\u0434\u043e\u043c \u043f\u043e\u0442\u043e\u043c\u043a\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430.", "Text_src": "The \"Data Output\" view shows formatted output text. It cannot be edited from this view.<br />
    <br />
    When the \"View &gt; Show Output Descendants\" command is toggled, the \"Data Output\" view will show an indented list with information about every descendant of a single selected node." }, "format": "HEAD_PARA", "uid": "f16fd9aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u044c \u00ab\u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb (Data Edit View)", "Name_src": "Data Edit View", "Text": "\u0412\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb (Data Edit) \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0438\u0437 \u043f\u043e\u043b\u0435\u0439 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0443\u0437\u043b\u0435. \u0412 \u043d\u0435\u0439 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0442\u0438\u043f\u044b \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 [\u0438\u043d\u0430\u0447\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f] \u0443\u0437\u043b\u043e\u0432. \u0422\u0438\u043f\u044b \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u044e\u0442\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u043b\u0435\u0439. \u041d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0437 \u043d\u0438\u0445 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u043b\u044f\u043c\u0438 \u0434\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a \u0434\u0440\u0443\u0433\u0438\u0435 (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043f\u043e\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430, \u0434\u0430\u0442\u044b, \u0441\u0441\u044b\u043b\u043e\u043a \u0438 \u0442.\u0434.) \u2014 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u043c\u0438 \u043c\u0435\u043d\u044e \u0438\u043b\u0438 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u044b\u043c\u0438 \u043e\u043a\u043d\u0430\u043c\u0438.", "Text_src": "The \"Data Edit\" view shows a text edit box for each data field within a node. It also shows the node types and the node titles. The types of edit boxes vary based on the field type. Some are just text editors, while others (such as choice fields, date fields, links, etc.) have pull-down menus or dialogs." }, "format": "HEAD_PARA", "uid": "f16fdabaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u044c \u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432\u00bb (Title List View)", "Name_src": "Title List View", "Text": "\u0412\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432\u00bb (\"Title List\") \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 [\u0438\u043d\u0430\u0447\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0439] \u0443\u0437\u043b\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c [\u0432 \u044d\u0442\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438] \u043a\u0430\u043a \u0432 \u043e\u0431\u044b\u0447\u043d\u043e\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435. \u0415\u0441\u043b\u0438 [\u043f\u0440\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0432 \u044d\u0442\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438] \u0432\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043d\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u0442\u043e [\u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u043c \u0434\u0435\u0440\u0435\u0432\u0435 \u0432 \u044d\u0442\u043e\u043c \u043c\u0435\u0441\u0442\u0435] \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u0443\u0437\u0435\u043b \u0441 \u044d\u0442\u0438\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c. \u0415\u0441\u043b\u0438 [\u043f\u0440\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0432 \u044d\u0442\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438] \u0441\u0442\u0440\u043e\u043a\u0430 \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0443\u0437\u0435\u043b \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f \u0438\u0437 \u0434\u0435\u0440\u0435\u0432\u0430.", "Text_src": "The \"Title List\" view shows a list of node titles that can be modified using typical text editor methods. If a new line is typed, a new node is created with that title. If a line is deleted, the corresponding node is removed from the tree." }, "format": "HEAD_PARA", "uid": "f16fdbc8a25a11e7b7c67054d2175f18" }, { "children": [ "f16fddbca25a11e7b7c67054d2175f18", "f16fdeb6a25a11e7b7c67054d2175f18", "997af664b58811e7ac243417ebd53aeb", "f16fdfb0a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435", "Name_src": "Editing" }, "format": "HEADINGS", "uid": "f16fdccca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041c\u0435\u043d\u044e \u00ab\u0423\u0437\u0435\u043b\u00bb (Node Menu)", "Name_src": "Node Menu", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u044b \u0432 \u043c\u0435\u043d\u044e \u00ab\u0423\u0437\u0435\u043b\u00bb (Node) \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043f\u043e \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044e \u043a \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0443\u0437\u043b\u0430\u043c \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441 \u0434\u0435\u0440\u0435\u0432\u043e\u043c, \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0449\u0435\u0439\u0441\u044f \u0441\u043b\u0435\u0432\u0430. \u0418\u043c\u0435\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043b\u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0443\u0437\u043b\u043e\u0432, \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 [\u0438\u043d\u0430\u0447\u0435 \u0438\u043c\u0435\u043d] \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0443\u0437\u043b\u043e\u0432. \u0412 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u044b \n\u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0434\u0435\u0440\u0435\u0432\u0430, \u043f\u0443\u0442\u0435\u043c \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0443\u0437\u043b\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u0443\u0440\u043e\u0432\u043d\u044f\u043c\u0438 \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0438\u0445 \u0432\u0432\u0435\u0440\u0445 \u0438\u043b\u0438 \u0432\u043d\u0438\u0437. \u041c\u043d\u043e\u0433\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u0442\u0440\u0430\u0433\u0438\u0432\u0430\u044e\u0442 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432.", "Text_src": "The commands in the \"Node\" menu operate on the selected nodes in the left tree view. There are commands to add or insert nodes, rename node titles and delete nodes. There are also commands to rearrange the tree by changing indent levels or moving nodes up or down. For many of the commands, the descendants of the selected nodes are also affected." }, "format": "HEAD_PARA", "uid": "f16fddbca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041c\u0435\u043d\u044e \u00ab\u041f\u0440\u0430\u0432\u043a\u0430\u00bb (Edit Menu)", "Name_src": "Edit Menu", "Text": "\u041c\u0435\u043d\u044e \u00ab\u041f\u0440\u0430\u0432\u043a\u0430\u00bb \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043e\u0442\u043c\u0435\u043d\u044b \u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u044b. \u041a\u043e\u043c\u0430\u043d\u0434\u044b \u0432\u044b\u0440\u0435\u0437\u0430\u043d\u0438\u044f, \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043f\u0440\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0441\u043f\u0440\u0430\u0432\u0430 (\u0435\u0441\u043b\u0438 \u043e\u043d\u0430 \u0432\u044b\u0431\u0440\u0430\u043d\u0430 \u0438 \u0430\u043a\u0442\u0438\u0432\u043d\u0430) \u0438\u043b\u0438 \u043a \u0443\u0437\u043b\u0430\u043c \u0432 \u0434\u0435\u0440\u0435\u0432\u0435.", "Text_src": "The edit menu includes undo and redo commands that can fix problems. Cut, copy and paste commands can operate either on text in the right-hand view (if selected or active) or to tree nodes." }, "format": "HEAD_PARA", "uid": "f16fdeb6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0411\u044b\u0441\u0442\u0440\u044b\u0439 \u0432\u044b\u0431\u043e\u0440 \u043a\u043e\u043c\u0430\u043d\u0434 (Shortcuts)", "Name_src": "Shortcuts", "Text": "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0443\u044e\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u0439 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u0438 \u043c\u044b\u0448\u0438, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0445\u0441\u044f \u043f\u0440\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0434\u0435\u0440\u0435\u0432\u0430. \u041f\u0435\u0440\u0435\u0442\u0430\u0449\u0438\u0442\u044c \u0438 \u043e\u0442\u043f\u0443\u0441\u0442\u0438\u0442\u044c (drag and drop) \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u0442 (\u0438\u043b\u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0435\u0442, \u0435\u0441\u043b\u0438 \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 Ctrl) \u0443\u0437\u043b\u044b. \u0429\u0435\u043b\u0447\u043e\u043a \u043f\u043e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u043c\u0443 \u0443\u0437\u043b\u0443 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0435\u0442 \u0435\u0433\u043e. \u041d\u0430\u0436\u0430\u0442\u0438\u0435 \u043a\u043d\u043e\u043f\u043a\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0443\u0434\u0430\u043b\u0438\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b. \u041f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u044d\u0442\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0432 \u043c\u0435\u043d\u044e \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b\u00bb (\"Tools > General Options\").", "Text_src": "There are several shortcuts for use in tree editing. Drag and drop will move (or copy if the Ctrl button is held) nodes. Clicking on a selected node will rename it. Pressing the delete key will remove the selected nodes. If desired, these shortcuts can be disabled in \"Tools &gt; General Options\"." }, "format": "HEAD_PARA", "uid": "f16fdfb0a25a11e7b7c67054d2175f18" }, { "children": [ "f16fe1cca25a11e7b7c67054d2175f18", "f16fe2c6a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0424\u0430\u0439\u043b\u044b", "Name_src": "Files" }, "format": "HEADINGS", "uid": "f16fe0b4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0428\u0430\u0431\u043b\u043e\u043d\u044b", "Name_src": "Templates", "Text": "\u041a\u043e\u0433\u0434\u0430 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b, \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e\u0449\u0435\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438\u0437 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0443\u0437\u043b\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a. \u0412 \u0448\u0430\u0431\u043b\u043e\u043d \u0414\u043b\u0438\u043d\u043d\u044b\u0439 \u0422\u0435\u043a\u0441\u0442 (Long Text) \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043e \u0432\u0442\u043e\u0440\u043e\u0435 \u043f\u043e\u043b\u0435 \u0442\u0438\u043f\u0430 \u0414\u043b\u0438\u043d\u043d\u044b\u0439 \u0422\u0435\u043a\u0441\u0442, \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u043e\u0435 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043e\u0431\u044a\u0435\u043c\u0430. \u0412 \u0434\u0440\u0443\u0433\u0438\u0445 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u0445 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0434\u043b\u044f \u043a\u043e\u043d\u0442\u0430\u043a\u0442\u043e\u0432, \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u043a\u043d\u0438\u0433 \u0438 \u0434\u0435\u043b.", "Text_src": "When starting a new file, a dialog box offers a choice of templates. The default has only a single text field for each node that contains the title. The Long Text template adds a second long text field for more output text. Other templates have various fields for contacts, book lists and to-do lists." }, "format": "HEAD_PARA", "uid": "f16fe1cca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0424\u0430\u0439\u043b\u044b \u041f\u0440\u0438\u043c\u0435\u0440\u043e\u0432", "Name_src": "Sample Files", "Text": "\u041f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0424\u0430\u0439\u043b > \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u041f\u0440\u0438\u043c\u0435\u0440\u00bb (\"File > Open Sample\") \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 TreeLine. \u0412 \u043d\u0438\u0445 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u0441\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u0447\u0435\u043c \u0432 \u0448\u0430\u0431\u043b\u043e\u043d\u0430\u0445 \u043d\u043e\u0432\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432, \u0438 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043e\u0431\u0440\u0430\u0437\u0446\u044b \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430.", "Text_src": "Various TreeLine sample files can be opened by using the \"File &gt; Open Sample\" command. These have more detail and example content than the new file templates." }, "format": "HEAD_PARA", "uid": "f16fe2c6a25a11e7b7c67054d2175f18" }, { "children": [ "f16fe4eca25a11e7b7c67054d2175f18", "f16fe5f0a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0422\u0438\u043f\u044b \u0414\u0430\u043d\u043d\u044b\u0445", "Name_src": "Data Types" }, "format": "HEADINGS", "uid": "f16fe3fca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f\u044b \u0443\u0437\u043b\u043e\u0432", "Name_src": "Node Types", "Text": "\u0412 \u0444\u0430\u0439\u043b\u0430\u0445 TreeLine \u043c\u043e\u0436\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u0435 \u0442\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u0430. \u041a\u0430\u0436\u0434\u044b\u0439 \u0442\u0438\u043f \u0443\u0437\u043b\u0430 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0438\u043c\u0435\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0432\u044b\u0432\u043e\u0434\u0430. \u0421\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0448\u0430\u0431\u043b\u043e\u043d\u043e\u0432 \u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432. \u0423\u0437\u043b\u0430\u043c \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0442\u0438\u043f \n\u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u0442\u0438\u043f \u0443\u0437\u043b\u0430\u00bb (\"Data > Set Node Type\").", "Text_src": "Multiple node data types can be defined in a TreeLine file. Each can contain different data fields and have different output formats. See the template and sample files for examples. Nodes can be set to a specific type using the \"Data &gt; Set Node Type\" command." }, "format": "HEAD_PARA", "uid": "f16fe4eca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432", "Name_src": "Type Config", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0422\u0438\u043f\u044b \u0414\u0430\u043d\u043d\u044b\u0445\u00bb (\"Data > Configure Data Types\") \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u0430, \u043f\u043e\u043b\u0435\u0439 \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0432\u043e\u0434\u0430. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0440\u0430\u0437\u0434\u0435\u043b\u0443 \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u043e\u043b\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438.", "Text_src": "The \"Data &gt; Configure Data Types\" command is used to modify node data types, fields and output formatting. Refer to the Detailed Usage section of the full documentation for details." }, "format": "HEAD_PARA", "uid": "f16fe5f0a25a11e7b7c67054d2175f18" }, { "children": [ "f16fe7e4a25a11e7b7c67054d2175f18", "f16fed0ca25a11e7b7c67054d2175f18", "f16ff2f2a25a11e7b7c67054d2175f18", "f1700936a25a11e7b7c67054d2175f18", "f1700f58a25a11e7b7c67054d2175f18", "f170146ca25a11e7b7c67054d2175f18", "f1701caaa25a11e7b7c67054d2175f18", "f170207ea25a11e7b7c67054d2175f18", "f170256aa25a11e7b7c67054d2175f18", "f1702c4aa25a11e7b7c67054d2175f18", "f170335ca25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u0445", "Name_src": "Detailed Usage" }, "format": "HEADINGS", "uid": "f16fe6fea25a11e7b7c67054d2175f18" }, { "children": [ "f16fe8dea25a11e7b7c67054d2175f18", "f16fe9e2a25a11e7b7c67054d2175f18", "f16feaf0a25a11e7b7c67054d2175f18", "f16fec08a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443 \u0438 \u041f\u043e\u0438\u0441\u043a", "Name_src": "Tree Navigation and Search" }, "format": "HEADINGS", "uid": "f16fe7e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0413\u043e\u0440\u044f\u0447\u0438\u0435 \u041a\u043b\u0430\u0432\u0438\u0448\u0438", "Name_src": "Keyboard Shortcuts", "Text": "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u044e\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u0431\u0445\u043e\u0434\u0430 \u0434\u0435\u0440\u0435\u0432\u0430. \u041a\u043b\u0430\u0432\u0438\u0448\u0438 \u0441\u043e \u0441\u0442\u0440\u0435\u043b\u043a\u0430\u043c\u0438 \u0432\u0432\u0435\u0440\u0445 \u0438 \u0432\u043d\u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u044e\u0442 \u0432\u044b\u0434\u0435\u043b\u0435\u043d\u0438\u0435. \u0421\u0442\u0440\u0435\u043b\u043a\u0438 \u0432\u043b\u0435\u0432\u043e \u0438 \u0432\u043f\u0440\u0430\u0432\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0442 \u0438 \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u044e\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0443\u0437\u0435\u043b. \u041a\u043b\u0430\u0432\u0438\u0448\u0438 \u00abHome\u00bb, \u00abEnd\u00bb, \u00abPage Up\u00bb \u0438 \u00abPage Down\u00bb \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443.
    \n
    \n\u0415\u0449\u0435 \u043e\u0434\u0438\u043d \u0441\u043f\u043e\u0441\u043e\u0431 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443 \u2014 \u0432\u0432\u0435\u0441\u0442\u0438 \u043f\u0435\u0440\u0432\u0443\u044e \u0431\u0443\u043a\u0432\u0443 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0432\u0438\u0434\u0438\u043c\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u043d\u0430 \u0431\u0443\u043a\u0432\u0443 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0439 \u0432\u044b\u0431\u043e\u0440.", "Text_src": "There are several keyboard commands that can be used for tree navigation. The up and down arrow keys move the selection. The left and right arrows open and close the current node. The \"Home\", \"End\", \"Page Up\" and \"Page Down\" keys can be used to move quickly through the tree.<br />
    <br />
    Another way to move through the tree is to type the first letter of a visible node title. Hitting the letter again highlights to the next possibility." }, "format": "HEAD_PARA", "uid": "f16fe8dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0412\u044b\u0431\u043e\u0440", "Name_src": "Selection", "Text": "\u041c\u043e\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443\u0437\u043b\u043e\u0432, \u0443\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044f \u043d\u0430\u0436\u0430\u0442\u043e\u0439 \u043a\u043b\u0430\u0432\u0438\u0448\u0443 CTRL \u0438\u043b\u0438 SHIFT \u043f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u043d\u043e\u0432\u043e\u0433\u043e \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0443\u0437\u043b\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u044b \u0438\u0437 \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u0440\u0438 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0438 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 CTRL. \u041f\u0440\u0438 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0438 SHIFT \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u0432\u044b\u0431\u043e\u0440 \u0432\u0441\u0435\u0445 \u0443\u0437\u043b\u043e\u0432 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u043c \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438. \u0410\u043a\u0442\u0438\u0432\u043d\u044b\u0439 \u0443\u0437\u0435\u043b \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b\u0448\u0438 \u0438\u043b\u0438 \u043b\u044e\u0431\u043e\u0433\u043e \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b.\n

    \n\u041a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0412\u0438\u0434 > \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439 \u0432\u044b\u0431\u043e\u0440\u00bb \u0438 \u00ab\u0412\u0438\u0434 > \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0432\u044b\u0431\u043e\u0440\u00bb \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u043c\u0435\u0436\u0434\u0443 \u0438\u0441\u0442\u043e\u0440\u0438\u0435\u0439 \u0432\u044b\u0431\u043e\u0440\u0430, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0434\u0435\u0440\u0435\u0432\u0443.", "Text_src": "Multiple nodes can be selected by holding down the CTRL or the SHIFT key when changing the active node. Individual nodes are added or removed from the selection when the CTRL key is held. The selection of all nodes between the old and new active nodes are toggled when SHIFT is held. The active node can be changed by using the mouse or by using any of the keyboard navigation methods.<br />
    <br />
    The \"View &gt; Previous Selection\" and \"View &gt; Next Selection\" commands can be used to toggle through a history of selections, allowing faster navigation through the tree." }, "format": "HEAD_PARA", "uid": "f16fe9e2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u0438\u0441\u043a", "Name_src": "Searching", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041f\u043e\u0438\u0441\u043a \u0442\u0435\u043a\u0441\u0442\u0430\u00bb \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043a\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442 \u0432 \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435. \u0412 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0432\u043e \u0432\u0441\u0435\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u0430 \u0438\u043b\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u0445 \u0443\u0437\u043b\u043e\u0432. \u0422\u0430\u043a\u0436\u0435 \u0435\u0441\u0442\u044c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0432\u044b\u0431\u043e\u0440\u0430 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0446\u0438\u0438 \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430. \u041f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u043e\u043f\u0446\u0438\u0438 \"\u041a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430\" \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0438\u0441\u043a \u0443\u0437\u043b\u043e\u0432, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u043b\u043e\u0432\u0430, \u043d\u0430\u0439\u0434\u0435\u043d\u043d\u044b\u0435 \u0432 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0443\u0437\u043b\u0430. \u041f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \"\u041f\u043e\u043b\u043d\u044b\u0435 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u0441\u043b\u043e\u0432\u0430\" \u0431\u0443\u0434\u0443\u0442 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0443\u0437\u043b\u044b \u0441 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0441\u043b\u043e\u0432\u0430\u043c\u0438 [\u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0449\u0438\u043c\u0438\u0441\u044f \u0447\u0430\u0441\u0442\u044c\u044e \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043b\u043e\u0432, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0441\u043b\u043e\u0432, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0438\u0441\u043a\u043e\u043c\u043e\u0435 \u043f\u043e\u043b\u043d\u043e\u0435 \u0441\u043b\u043e\u0432\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0441\u043e\u0441\u0442\u0430\u0432\u0435 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u043b\u043e\u0432, \u043e\u0442\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u0441\u0438\u043c\u0432\u043e\u043b\u0430\u043c\u0438, \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043e\u0442 \u0431\u0443\u043a\u0432], \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0435\u0441\u044f \u0432 \u043b\u044e\u0431\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0443\u0437\u043b\u0430. \u0412\u044b\u0431\u043e\u0440 \"\u041f\u043e\u043b\u043d\u0430\u044f \u0444\u0440\u0430\u0437\u0430\" \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442\u044c \u043a \u043f\u043e\u0438\u0441\u043a\u0443 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u0439 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u0439 \u0444\u0440\u0430\u0437\u0435 \u0432 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0441\u043b\u043e\u0432. \u0418, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0432\u044b\u0431\u043e\u0440 \"\u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435\" \u0431\u0443\u0434\u0435\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u043f\u043e\u0438\u0441\u043a \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 Python.\n

    \n\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u0423\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u043f\u043e\u0438\u0441\u043a\u00bb \u0434\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u0432 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u0445 \u0442\u0438\u043f\u0430\u0445 \u0438 \u043f\u043e\u043b\u044f\u0445 \u0443\u0437\u043b\u043e\u0432. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0434\u043b\u044f \u0442\u043e\u0447\u043d\u043e\u0433\u043e \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0438\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u043c\u0443 \u0438\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435\u043c\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e, \u0438\u043b\u0438 \u0447\u0430\u0441\u0442\u0438 \u0438\u0441\u043a\u043e\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u044b \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f. \u0410 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b True / False \u0434\u0430\u044e\u0442 \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u0412 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u043b\u0435\u0439. \u041c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0430\u0432\u0438\u043b \u043f\u043e\u0438\u0441\u043a\u0430, \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u00ab\u0438\u00bb \u0438\u043b\u0438 \u00ab\u0438\u043b\u0438\u00bb. \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u00ab\u0412\u0441\u0435 \u0442\u0438\u043f\u044b\u00bb \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u043f\u043e \u043f\u043e\u043b\u044f\u043c \u0432\u0441\u0435\u0445 \u0442\u0438\u043f\u043e\u0432, \u0442\u0430\u043a \u0447\u0442\u043e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0442\u0438\u043f\u043e\u0432 \u0443\u0437\u043b\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432 \u043e\u0434\u0438\u043d \u043f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441. \u0423\u0441\u043b\u043e\u0432\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043b\u043e\u0436\u043d\u044b\u043c \u0434\u043b\u044f \u0442\u0438\u043f\u043e\u0432 \u0443\u0437\u043b\u043e\u0432, \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0445 \u044d\u0442\u043e \u0438\u043c\u044f \u043f\u043e\u043b\u044f [\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043f\u043e\u0438\u0441\u043a \u043f\u043e False \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d \u043d\u0435\u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e].\n

    \n\u0422\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d\u0438\u044f \u0431\u044b\u0441\u0442\u0440\u043e\u0433\u043e \u043f\u043e\u0448\u0430\u0433\u043e\u0432\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430 \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c \u0443\u0437\u043b\u043e\u0432. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u043d \u043f\u0440\u0438\u0432\u044f\u0437\u0430\u043d \u043a \"ctrl + /\". [\u041f\u0440\u0438 \u043d\u0430\u0436\u0430\u0442\u0438\u0438 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u0438 \u043a\u043b\u0430\u0432\u0438\u0448 \u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u043d\u0438\u0437\u0443 \u0433\u043b\u0430\u0432\u043d\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0430\u043a\u0442\u0438\u0432\u0438\u0437\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u0435 \u0432\u0432\u043e\u0434\u0430 \u0438\u0441\u043a\u043e\u043c\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f]. \u0417\u0430\u0442\u0435\u043c \u043f\u043e \u043c\u0435\u0440\u0435 \u0432\u0432\u043e\u0434\u0430 \u0441\u0442\u0440\u043e\u043a\u0438 \u043f\u043e\u0438\u0441\u043a\u0430 \u0438\u0449\u0443\u0442\u0441\u044f \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438. \u041a\u043b\u0430\u0432\u0438\u0448\u0438 F3 \u0438 \"shift + F3\" \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u0438\u043b\u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c\u0443 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.", "Text_src": "The \"Tools &gt; Find Text\" command will search for text within the tree structure. The dialog box has options for searching all of the node data or only the node titles. There are also options for how to interpret the search text. Key words will match nodes with the search words found anywhere in the node. Key full words will only match complete words anywhere in the node. Full phrase will only match the complete phrase in the proper sequence. Finally, the regular expression option will search using Python regular expressions.<br />
    <br />
    The \"Tools &gt; Conditional Find\" command will search in particular node types and node fields. Various comparison operators can be selected to exactly match, to match a greater or lesser value, or part of the value. And the True/False operators give the same result regardless of the values. In general, the value is interpreted using the edit format for special field types. Multiple rules can be added, connected with logical \"and\" or \"or\" operators. The \"All Types\" option makes fields from every type are available, so that multiple node types to be part of the same search. The condition will be false for node types that do not contain that field name.<br />
    <br />
    There is also a quick, incremental search of node titles. By default, it's bound to ctrl+/. Then, matching titles are found as the search string is typed. The F3 and shift+F3 keys can be used to go to the next or previous matches, respectively." }, "format": "HEAD_PARA", "uid": "f16feaf0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0424\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u044f", "Name_src": "Filtering", "Text": "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0434\u0432\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u0446\u0438\u0438 \u0443\u0437\u043b\u043e\u0432: \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440\u00bb \u0438 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u0423\u0441\u043b\u043e\u0432\u043d\u044b\u0439 \u0444\u0438\u043b\u044c\u0442\u0440\u00bb. \u041e\u043d\u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0438\u0441\u043a\u0430, \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0432\u044b\u0448\u0435, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043e\u043d\u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u0432\u0441\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0435 \u0443\u0437\u043b\u044b \u0432 \u043f\u043b\u043e\u0441\u043a\u043e\u043c \u0441\u043f\u0438\u0441\u043a\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043c\u0435\u043d\u044f\u0435\u0442 \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0432 \u0435\u0433\u043e \u043f\u0430\u043d\u0435\u043b\u0438. \u0412 \u044d\u0442\u043e\u0439 \u0444\u043e\u0440\u043c\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0443\u0437\u043b\u044b \u043c\u043e\u0433\u0443\u0442 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c\u0441\u044f \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0417\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u00bb, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 \u0432\u0438\u0434\u0435 \u0434\u0435\u0440\u0435\u0432\u0430.
    \n
    \n\u041f\u043e\u0438\u0441\u043a\u043e\u0432\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0434\u043b\u044f \u0443\u0441\u043b\u043e\u0432\u043d\u043e\u0433\u043e \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0443\u0441\u043b\u043e\u0432\u043d\u043e\u0433\u043e \u0444\u0438\u043b\u044c\u0442\u0440\u0430 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u044b\u0445 \u043e\u043a\u043d\u0430\u0445 \u0438 \u0441\u043d\u043e\u0432\u0430 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044c \u0432 \u0434\u0440\u0443\u0433\u043e\u0435 \u0432\u0440\u0435\u043c\u044f.", "Text_src": "There are two filtering commands, \"Tools &gt; Text Filter\" and \"Tools &gt; Conditional Filter\". They work like the corresponding search commands above, except that they show all of the matching nodes in a flat list that replaces the tree view. The nodes can be selected and edited from this view. Use the \"End Filter\" button to restore the full tree view.<br />
    <br />
    Searches for Conditional Find and Conditional Filter can be saved in the dialog boxes and loaded again at another time." }, "format": "HEAD_PARA", "uid": "f16fec08a25a11e7b7c67054d2175f18" }, { "children": [ "f16fedfca25a11e7b7c67054d2175f18", "f16feef6a25a11e7b7c67054d2175f18", "f16feffaa25a11e7b7c67054d2175f18", "f16ff0f4a25a11e7b7c67054d2175f18", "f16ff1e4a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0422\u0438\u043f\u043e\u0432 \u0423\u0437\u043b\u043e\u0432", "Name_src": "Defining Node Types" }, "format": "HEADINGS", "uid": "f16fed0ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u043f\u0438\u0441\u043e\u043a \u0422\u0438\u043f\u043e\u0432", "Name_src": "Type List", "Text": "\u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u0442\u0438\u043f\u043e\u0432\u00bb \u2014 \u044d\u0442\u043e \u043f\u0435\u0440\u0432\u0430\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0422\u0438\u043f\u044b \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u0421\u043f\u0438\u0441\u043e\u043a \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043d\u043e\u043f\u043e\u043a, \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u0441\u043f\u0440\u0430\u0432\u0430. \u041c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0442\u0438\u043f\u044b, \u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0442\u0438\u043f\u044b \u043c\u043e\u0436\u043d\u043e \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u044f\u0442\u044c.", "Text_src": "The \"Type List\" is the first tab of the \"Data > Configure Types Dialog\". The list of data types can be modified by the buttons on the right. New types can be added, and existing types can be copied, renamed or deleted." }, "format": "HEAD_PARA", "uid": "f16fedfca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u0430", "Name_src": "Type Config", "Text": "\u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u0430\u00bb \u2014 \u044d\u0442\u043e \u0432\u0442\u043e\u0440\u0430\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u041e\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u044b\u0431\u043e\u0440 \u0442\u0438\u043f\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0443\u0437\u043b\u0430 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e. \u0415\u0441\u043b\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e, \u043e\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432 \u0441 \u044d\u0442\u0438\u043c \u0442\u0438\u043f\u043e\u043c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f. \u0415\u0441\u043b\u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u00ab[\u041d\u0435\u0442]\u00bb, \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0443\u0437\u043b\u044b \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0431\u043e \u0442\u0438\u043f \u0441\u0435\u0441\u0442\u0440\u0438\u043d\u0441\u043a\u0438\u0445 \u0443\u0437\u043b\u043e\u0432, \u043b\u0438\u0431\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445. \n

    \n\u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u0421\u043c\u0435\u043d\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u043e\u043a\u00bb \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u043e\u043a, \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0439 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0432\u044b\u0431\u043e\u0440\u00bb \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u0437\u043d\u0430\u0447\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0434\u043b\u044f \u0437\u043d\u0430\u0447\u043a\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u00ab\u041d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d\u00bb, \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0437\u043d\u0430\u0447\u043e\u043a \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f. \u0427\u0442\u043e\u0431\u044b \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u043a\u0438 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435, \u0432 \u043e\u043a\u043d\u0435 \u00ab\u041e\u0431\u0449\u0438\u0435 \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b\u00bb \u043d\u0443\u0436\u043d\u043e \u043e\u0442\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u00ab\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0437\u043d\u0430\u0447\u043a\u0438 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435\u00bb.\n

    \n\u0412 \u044d\u0442\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u0438 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u0443\u0441\u0442\u044b\u0445 \u0441\u0442\u0440\u043e\u043a \u043c\u0435\u0436\u0434\u0443 \u0443\u0437\u043b\u0430\u043c\u0438, \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0442\u0435\u0433\u043e\u0432 HTML \u043f\u0440\u0438 \u0432\u044b\u0432\u043e\u0434\u0435 \u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043c\u0430\u0440\u043a\u0435\u0440\u043e\u0432 \u0438\u043b\u0438 \u0442\u0430\u0431\u043b\u0438\u0446.", "Text_src": "\"Type Config\" is the second tab of the Configure Types Dialog. It contains a selection for the default child type. If set, this will be the initial type used for new children with this type of parent. If set to \"[None]\", children will default to either the type of their siblings or their parent.
    \n
    \nThe \"Change Icon\" button allows the selection of a custom tree icon for this data type. The \"Clear Select\" button on the icon dialog can be used to set the icon to \"None\", so that no icon will be displayed for this type. To avoid showing any tree icons, the \"Show icons in the tree view\" general option can be unset.
    \n
    \nThere are also options here for adding blanks lines between nodes, allowing HTML tags in the common format text, and changing the output to add bullets or tables." }, "format": "HEAD_PARA", "uid": "f16feef6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u0435\u0439", "Name_src": "Field List", "Text": "\u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u0435\u0439\u00bb \u2014 \u044d\u0442\u043e \u0442\u0440\u0435\u0442\u044c\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u0421\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u0435\u0439 \u0432 \u0442\u0438\u043f\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043d\u043e\u043f\u043e\u043a \u0441\u043f\u0440\u0430\u0432\u0430. \u041c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044f, \u0430 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u043b\u044f \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c, \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u0443\u0434\u0430\u043b\u044f\u0442\u044c. \u0422\u0430\u043a\u0436\u0435 \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0435 \u0443\u0437\u043b\u043e\u0432, \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u044b \u043a\u043b\u044e\u0447\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438.", "Text_src": "The \"Field List\" is the third tab of the Configure Types Dialog. The list of fields within a data type can be modified by using the buttons on the right. New fields can be added, and existing fields can be moved, renamed or deleted. Sort keys can also be defined to specify the fields that are compared when nodes are sorted." }, "format": "HEAD_PARA", "uid": "f16feffaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u041f\u043e\u043b\u044f", "Name_src": "Field Config", "Text": "\u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u041f\u043e\u043b\u044f\u00bb \u2014 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u0430\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u0412 \u0434\u0430\u043d\u043d\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0442\u0438\u043f \u043f\u043e\u043b\u044f \u0438 \u0444\u043e\u0440\u043c\u0430\u0442 \u0435\u0433\u043e \u0432\u044b\u0432\u043e\u0434\u0430, \u0435\u0441\u043b\u0438 \u043e\u043d \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u043c \u043a \u043f\u043e\u043b\u044e. \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0438\u0439 \u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u044e\u0449\u0438\u0439 \u0442\u0435\u043a\u0441\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c \u043f\u043e\u043b\u044f, \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043d\u043e\u0432\u044b\u0445 \u0443\u0437\u043b\u043e\u0432. \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c\u044b\u0445 \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435. \u0418 \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0434\u043b\u044f \u0440\u0430\u0441\u043f\u043e\u0437\u043d\u0430\u0432\u0430\u043d\u0438\u044f \u0442\u0435\u0433\u043e\u0432 HTML \u0432 \u043f\u043e\u043b\u044f\u0445 \u0412\u044b\u0431\u043e\u0440, \u0410\u0432\u0442\u043e\u0412\u044b\u0431\u043e\u0440, \u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f, \u0410\u0432\u0442\u043e\u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f \u0438 \u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0442\u0435\u0433\u043e\u0432 HTML. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b (\u0443\u0433\u043b\u043e\u0432\u044b\u0435 \u0441\u043a\u043e\u0431\u043a\u0438 \u0438 \u043a\u0430\u0432\u044b\u0447\u043a\u0438), \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u043b\u0438\u0441\u044c \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u043f\u043e\u043b\u044f.", "Text_src": "\"Field Config\" is the fourth tab of the Configure Types Dialog. The field type and its output format string can be set, if applicable to the field. Extra prefix and suffix text to be output with the field can also be set, and a default field value for new nodes can be entered. The number of lines displayed in the editor for the field can also be specified. Finally, an option to evaluate HTML tags can be set to recognize HTML tags in Choice, AutoChoice, Combination, AutoCombination and RegularExpression fields. If this is set, special characters (angled brackets and quotation marks) will need to be manually escaped to show up in the field text." }, "format": "HEAD_PARA", "uid": "f16ff0f4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0412\u044b\u0432\u043e\u0434", "Name_src": "Output", "Text": "\u00ab\u0412\u044b\u0432\u043e\u0434\u00bb \u2014 \u044d\u0442\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u0412 \u043b\u0435\u0432\u043e\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0435 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u044b [\u0438\u043c\u0435\u044e\u0449\u0438\u0435\u0441\u044f \u0432 \u0443\u0437\u043b\u0435] \u043f\u043e\u043b\u044f. \u0412 \u043f\u0440\u0430\u0432\u043e\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0435 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 (\u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0443\u0437\u043b\u0430 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435) \u0438 \u0432\u044b\u0432\u043e\u0434\u0430 \u0443\u0437\u043b\u0430. \u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c\u0438 \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438 \u0441 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438. \u041f\u043e\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a \"{* field_name *}\". \u041f\u043e\u043b\u044f, \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 (\u0432\u043e\u0437\u043c\u043e\u0436\u0435\u043d \u0432\u044b\u0431\u043e\u0440 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u043f\u0440\u0438 \u0443\u0434\u0435\u0440\u0436\u0430\u043d\u0438\u0438 \u043a\u043b\u0430\u0432\u0438\u0448\u0438 Ctrl \u0438\u043b\u0438 Shift \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0441 \u0449\u0435\u043b\u0447\u043a\u043e\u043c \u043c\u044b\u0448\u0438), \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043f\u043e\u043b\u0435 \u00ab\u0424\u043e\u0440\u043c\u0430\u0442 \u0412\u044b\u0432\u043e\u0434\u0430\u00bb \u0432 \u043f\u043e\u0437\u0438\u0446\u0438\u044e \u043a\u0443\u0440\u0441\u043e\u0440\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043d\u043e\u043f\u043a\u0438 \u00ab>>\u00bb. \u0421\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043f\u043e\u043b\u0435 \u043f\u043e\u0434 \u043a\u0443\u0440\u0441\u043e\u0440\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043d\u043e\u043f\u043a\u0438 \"<<\".", "Text_src": "\"Output\" is the last tab of the Configure Types Dialog. The left half of the dialog shows the fields. The right half shows the formatting for the title (used for the node text in the tree view) and the node output. The formatting consists of text lines with embedded fields. The fields are shown as \"{*field_name*}\". The fields that are selected in the list (multiple fields can be selected by holding Ctrl or Shift keys while clicking) can be added to a format at the cursor position with the \">>\" keys. The field reference at the cursor can be removed with the \"<<\" keys." }, "format": "HEAD_PARA", "uid": "f16ff1e4a25a11e7b7c67054d2175f18" }, { "children": [ "f16ff3e2a25a11e7b7c67054d2175f18", "f16ff4dca25a11e7b7c67054d2175f18", "f16ff5f4a25a11e7b7c67054d2175f18", "f16ff7c0a25a11e7b7c67054d2175f18", "f16ff8f6a25a11e7b7c67054d2175f18", "f16ff9faa25a11e7b7c67054d2175f18", "f17005f8a25a11e7b7c67054d2175f18", "f1700710a25a11e7b7c67054d2175f18", "f16ffc02a25a11e7b7c67054d2175f18", "f16ffd06a25a11e7b7c67054d2175f18", "f16ffe14a25a11e7b7c67054d2175f18", "f16ffb08a25a11e7b7c67054d2175f18", "f16fff18a25a11e7b7c67054d2175f18", "f1700008a25a11e7b7c67054d2175f18", "f1700102a25a11e7b7c67054d2175f18", "f1700206a25a11e7b7c67054d2175f18", "f1700300a25a11e7b7c67054d2175f18", "f1700404a25a11e7b7c67054d2175f18", "f17004fea25a11e7b7c67054d2175f18", "f170081ea25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0422\u0438\u043f\u044b \u041f\u043e\u043b\u0435\u0439", "Name_src": "Field Types" }, "format": "HEADINGS", "uid": "f16ff2f2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u041f\u043e\u043b\u0435\u0439", "Name_src": "Field Options", "Text": "\u0422\u0438\u043f \u043f\u043e\u043b\u044f \u0438 \u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u0434\u0430\u044e\u0442\u0441\u044f \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043b\u044f\u00bb \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u0412 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043d\u0438\u0436\u0435 \u0430\u0431\u0437\u0430\u0446\u0430\u0445 \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u043b\u0435\u0439. \n
    \n
    \n\u0414\u043b\u044f \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u043b\u0435\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0435\u0435 \u0432\u044b\u0432\u043e\u0434\u0430. \u0427\u0442\u043e\u0431\u044b \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0445\u0441\u044f \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0421\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e \u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e\u00bb. \u0417\u0430\u043f\u0438\u0441\u0438 \u0432 \u043f\u043e\u043b\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442\u0443, \u043f\u0440\u0438\u0432\u0435\u0434\u0443\u0442 \u043a \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044e \u0441\u0438\u043d\u0435\u0433\u043e \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432 \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u043b\u0435\u0432\u043e\u043c \u0443\u0433\u043b\u0443 \u043f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u043f\u0440\u0438 \u0432\u044b\u0432\u043e\u0434\u0435 \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u044b \u043d\u0430 \u00ab#####\u00bb.", "Text_src": "The field type and options are set in the \"Field Config\" tab of the \"Data > Configure Types Dialog\". The many different field types are described in the paragraphs below.
    \n
    \nSeveral of the field types use a formatting string to define their output. For a list of available formatting characters, use the \"Format Help\" button. Entries in the data editor which do not match the format will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with \"#####\"." }, "format": "HEAD_PARA", "uid": "f16ff3e2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0422\u0435\u043a\u0441\u0442", "Name_src": "Text Type", "Text": "\u0422\u0438\u043f \u043f\u043e\u043b\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u2014 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u043f\u043e\u043b\u0435. \u041e\u043d\u043e \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u0447\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u043f\u043e\u043b\u0435\u0439. \u042d\u0442\u0438 \u043f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0432 \u0444\u043e\u0440\u043c\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043f\u043e\u043b\u0435\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u0412 \u043c\u0435\u043d\u044e \u00ab\u0424\u043e\u0440\u043c\u0430\u0442\u00bb (\u0430 \u0442\u0430\u043a\u0436\u0435 \u0432 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u043c \u043c\u0435\u043d\u044e) \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043c\u0430\u043d\u0434 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0442\u0438\u043b\u0435\u0439 \u0448\u0440\u0438\u0444\u0442\u0430 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432\u043d\u0435\u0448\u043d\u0438\u0445 \u0438\u043b\u0438 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0445 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043e\u043a. \u0412\u044b\u0441\u043e\u0442\u0430 \u043f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0442\u0440\u043e\u043a \u0442\u0435\u043a\u0441\u0442\u0430 [, \u043a\u043e\u0433\u0434\u0430 \u0438\u0445 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u0435\u0432\u044b\u0448\u0430\u0435\u0442 \u0432\u044b\u0441\u043e\u0442\u0443 \u043f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f] \u043f\u0440\u0438 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0438 \u043e\u043a\u043d\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0432\u044b\u0441\u043e\u0442\u0443 \u043f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u044f\u0432\u043d\u043e \u0437\u0430\u0434\u0430\u0442\u044c \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043b\u044f\u00bb.", "Text_src": "The default field type is a text field. It is the most commonly used field. These fields are edited using edit boxes in the data editor view. There are several commands in the Format menu (and also in the context menu) for setting the font style and adding external or internal links. The edit box height expands when re-displayed after adding several lines of text. The minimum edit box height can also be set explicitly in the \"Field Config\" tab." }, "format": "HEAD_PARA", "uid": "f16ff4dca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0422\u0435\u043a\u0441\u0442 \u0441 \u0440\u0430\u0437\u043c\u0435\u0442\u043a\u043e\u0439 HTML", "Name_src": "HTML Text Type", "Text": "\u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 \u0442\u0435\u043a\u0441\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u044b\u0435 HTML-\u0442\u0435\u0433\u0438. \u0427\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c\u0438 \u0442\u0435\u0433\u0430\u043c\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \"<b> \u0436\u0438\u0440\u043d\u044b\u0439 </b>\", \"<u> \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435 </u>\", \"\u0440\u0430\u0437\u0440\u044b\u0432 \u0441\u0442\u0440\u043e\u043a\u0438 <br/>\", \"\u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u0438\u043d\u0438\u044f <hr/>\" \u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0442\u0435\u0433\u0438 \u0448\u0440\u0438\u0444\u0442\u043e\u0432. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0431\u043b\u043e\u0447\u043d\u044b\u0445 \u0442\u0435\u0433\u043e\u0432. \u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u043a\u0430\u0440\u0435\u0442\u043a\u0438 \u0438\u0433\u043d\u043e\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f, \u0430 \u043d\u0435\u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u00ab<\u00bb, \u00ab>\u00bb \u0438 \"&\" \u043d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f.", "Text_src": "This type allows simple HTML tags to be used in the text. Commonly used tags include \"<b>bold</b>\", \"<u>underline</u>\", \"line break<br/>\", \"horizontal line<hr/>\", and various font tags. Complex block tags should generally be avoided. Carriage returns are ignored, and non-escaped \"<\", \">\" and \"&\" symbols do not display. " }, "format": "HEAD_PARA", "uid": "f16ff5f4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u0434\u043d\u043e\u0441\u0442\u0440\u043e\u0447\u043d\u044b\u0439 \u0422\u0435\u043a\u0441\u0442", "Name_src": "One Line Text Type", "Text": "\u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0434\u043b\u0438\u043d\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0430 \u043e\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439. \u0412 \u043d\u0435\u043c \u043d\u0435 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0442\u0430 \u043a\u0430\u0440\u0435\u0442\u043a\u0438 [\u043f\u0435\u0440\u0435\u0432\u043e\u0434 \u0441\u0442\u0440\u043e\u043a\u0438], \u043d\u043e \u043d\u0435 \u0437\u0430\u043f\u0440\u0435\u0449\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u043e\u0432 \u043e\u0434\u043d\u043e\u0439 \u0434\u043b\u0438\u043d\u043d\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438.", "Text_src": "This type restricts the text length to a single line. It does not allow carriage returns but does not restrict line wrapping of a single long line." }, "format": "HEAD_PARA", "uid": "f16ff7c0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0435\u043a\u0441\u0442 \u0441 \u041c\u0435\u0436\u0434\u0443\u0441\u0442\u0440\u043e\u0447\u043d\u044b\u043c\u0438 \u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430\u043c\u0438", "Name_src": "Spaced Text Type", "Text": "\u0423\u0437\u043b\u044b \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0442\u0435\u043a\u0441\u0442 \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442 \u0432\u0441\u0435 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u044b. \u0414\u0440\u0443\u0433\u043e\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u043d\u0435 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f. \u041f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043f\u043e\u043b\u044f \u043c\u043e\u0436\u0435\u0442 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0448\u0440\u0438\u0444\u0442\u044b\u00bb, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0448\u0440\u0438\u0444\u0442 \u0441 \u043e\u0434\u0438\u043d\u0430\u0440\u043d\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u043e\u043c.", "Text_src": "This type holds plain text and preserves all spacing. Other formatting of the text is not permitted. It could be useful to use the \"Tools > Customize Fonts\" command to set the editor font to a mono-spaced font when using this field type." }, "format": "HEAD_PARA", "uid": "f16ff8f6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0427\u0438\u0441\u043b\u043e", "Name_src": "Number Type", "Text": "\u0412 \u0447\u0438\u0441\u043b\u043e\u0432\u043e\u043c \u0442\u0438\u043f\u0435 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0432 \u043f\u043e\u043b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0447\u0438\u0441\u0435\u043b. \u0414\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0432\u044b\u0432\u043e\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0430\u044f \u0438\u0437 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 \u00ab#\u00bb (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0446\u0438\u0444\u0440\u0430) \u0438 \u00ab0\u00bb (\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0446\u0438\u0444\u0440\u0430). \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0438\u0441\u043b\u043e \u043f\u0438, \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0435 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u0442\u0440\u043e\u043a\u0438 \u00ab#. #\u00bb, \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043a\u0430\u043a \u00ab3.1\u00bb, \u0430 \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u00ab00.00\u00bb \u043a\u0430\u043a \u00ab03.14\u00bb. \u041d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0446\u0438\u0444\u0440\u044b \u0441\u043b\u0435\u0432\u0430 \u043e\u0442 \u0434\u0435\u0441\u044f\u0442\u0438\u0447\u043d\u043e\u0439 \u0442\u043e\u0447\u043a\u0438 \u043d\u0435 \u0443\u0441\u0435\u043a\u0430\u044e\u0442\u0441\u044f, \u0442\u0430\u043a \u043a\u0430\u043a \u044d\u0442\u043e \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u043d\u0435\u0432\u0435\u0440\u043d\u043e\u043c\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0443. \u041d\u043e \u0431\u0443\u0434\u044c\u0442\u0435 \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u044b, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u0435\u0441\u044f\u0442\u0438\u0447\u043d\u044b\u0445 \u0437\u043d\u0430\u043a\u043e\u0432 (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043b\u0438 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445), \u0447\u0442\u043e\u0431\u044b \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u0438\u044f.\n
    \n
    \n\u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u0441\u0438\u043c\u0432\u043e\u043b \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u0441\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u043a\u0430\u0437\u0430\u043d \u043a\u0430\u043a \".\" \u0438\u043b\u0438 \",\". \u0414\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f \u0442\u044b\u0441\u044f\u0447 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u00ab\\\u00bb \u0438\u043b\u0438 \u00ab\\.\u00bb. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043e \u043a\u0430\u043a \u00ab# \\, ### \\, ###. ##\u00bb \u0438\u043b\u0438 \u043a\u0430\u043a \u00ab# \\. ### \\. ###, ##\u00bb. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0421\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e\u00bb \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u043f\u043e\u043b\u044f.\n
    \n
    \n\u0412 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432, \u0432 \u0447\u0438\u0441\u043b\u043e\u0432\u043e\u043c \u0442\u0438\u043f\u0435 \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0432\u043e\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u0430\u043a\u0436\u0435 \u0438 \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u0420\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u043b\u044e\u0431\u0430\u044f \u043d\u043e\u0432\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0441 \u043f\u0440\u0438\u0435\u043c\u043b\u0435\u043c\u044b\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e (\u043d\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u0441\u0438\u043c\u0432\u043e\u043b \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u0438\u044f).", "Text_src": "In the number type, special characters in the format define the display of the numbers. The format uses a string of \"#\" (optional digit) and \"0\" (required digit) characters to define the output formatting. For example, pi formatted with \"#.#\" is \"3.1\" and formatted with \"00.00\" is \"03.14\". Regardless of the formatting, digits to the left of the decimal point are not truncated, since that would display an incorrect result. But use care to show enough decimal places (either optional or required) to avoid problems with round-off error.
    \n
    \nThe radix character can be specified as either \".\" or \",\" to handle internationalization. For use as a thousands separator, use \"\\,\" or \"\\.\". For example, a large number may be formatted as \"#\\,###\\,###.##\" or as \"#\\.###\\.###,##\". Press the \"Format Help\" button from the field format dialog for more formatting details.
    \n
    \nUnlike most other formats, the number type also uses the output format for display in the Data Editor. Of course, any new entry with a reasonable format is correctly interpreted (but the correct radix character must be used)." }, "format": "HEAD_PARA", "uid": "f16ff9faa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0422\u0438\u043f", "Name_src": "Boolean Type", "Text": "\u041f\u043e\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0434\u0432\u0430 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0430 \u0432\u044b\u0431\u043e\u0440\u0430, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c \u0438\u0441\u0442\u0438\u043d\u0430 / \u043b\u043e\u0436\u044c. \u041c\u0435\u043d\u044e \u0441\u043f\u0440\u0430\u0432\u043a\u0438 \u043f\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u043f\u043e\u043b\u0435\u0439 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0435 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0430, \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u00ab\u0434\u0430 / \u043d\u0435\u0442\u00bb, \u00ab\u0438\u0441\u0442\u0438\u043d\u0430 / \u043b\u043e\u0436\u044c\u00bb \u0438 \u00ab1/0\u00bb, \u043d\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0432\u0432\u0435\u0441\u0442\u0438 \u0441\u0432\u043e\u044e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e \u043f\u0430\u0440\u0443 \u0442\u0435\u0440\u043c\u0438\u043d\u043e\u0432. \u041f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043b\u0438\u0431\u043e \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435, \u043b\u0438\u0431\u043e \u0432 \u043b\u044e\u0431\u043e\u0439 \u0438\u0437 \u0442\u0438\u043f\u0438\u0447\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0430.", "Text_src": "This type gives two choices corresponding to true/false values. The format help menu includes typical values such as \"yes/no\", \"true/false\" and \"1/0\", but users can also enter their own word pair. The data editor boxes will accept either the currently set format or any of the typical values." }, "format": "HEAD_PARA", "uid": "f16ffb08a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0414\u0430\u0442\u0430", "Name_src": "Date Type", "Text": "\u0412 \u043f\u043e\u043b\u044f\u0445 \u0441 \u0442\u0438\u043f\u043e\u043c \u0434\u0430\u0442\u0430 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u0432\u0441\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0441 \"%\") \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u0430\u043a \u0438 \u0432 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u044f\u0445. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0421\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e\u00bb \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u043e\u043b\u044f. \u041d\u0435\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0432\u044b\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0442\u0430\u043a\u0438\u043c\u0438, \u043a\u0430\u043a \u043e\u043d\u0438 \u0435\u0441\u0442\u044c.\n
    \n
    \n\u0422\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b > \u0424\u043e\u0440\u043c\u0430\u0442\u044b \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb. \u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u0435\u0439 \u0434\u0430\u0442\u044b \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u043c\u0435\u044e\u0449\u0438\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430, \u043d\u043e \u0432 \u0434\u0430\u0442\u0430\u0445 \u0434\u043e\u043b\u0436\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u043d\u044c\u2014\u043c\u0435\u0441\u044f\u0446\u2014\u0433\u043e\u0434. \u0422\u0430\u043a\u0436\u0435 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0444\u043e\u0440\u043c\u0430\u0442 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u0442 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0434\u043d\u0438 \u043d\u0435\u0434\u0435\u043b\u0438.\n
    \n
    \n\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u00ab\u0421\u0435\u0439\u0447\u0430\u0441\u00bb \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u0434\u0430\u0442\u044b \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0443\u0437\u043b\u0430.", "Text_src": "In the date field type, special characters in the format (all starting with \"%\") are replaced by elements of the data, similar to number fields. Press the \"Format Help\" button from the field format dialog for formatting details. Non-special characters will be output as themselves.
    \n
    \nThere is also an edit format under \"Tools > General Options > Data Editor Formats\". This controls how date fields are displayed in the Data Editor view. Generally, entries in the data editor with various formats will be correctly interpreted regardless of this setting, but dates must use the correct day-month-year sequence. Also note that the date editor format does not support days of the week.
    \n
    \nA default initial field value of \"Now\" can be used to enter the date of node creation." }, "format": "HEAD_PARA", "uid": "f16ffc02a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0412\u0440\u0435\u043c\u044f", "Name_src": "Time Type", "Text": "\u0412 \u043f\u043e\u043b\u044f\u0445 \u0441 \u0442\u0438\u043f\u043e\u043c \u0432\u0440\u0435\u043c\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u0432\u0441\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0441 \"%\") \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u0430\u043a \u0438 \u0432 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0445 \u043f\u043e\u043b\u044f\u0445. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0421\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e\u00bb \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u043e\u043b\u044f. \u041d\u0435\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0432\u044b\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0442\u0430\u043a\u0438\u043c\u0438, \u043a\u0430\u043a \u043e\u043d\u0438 \u0435\u0441\u0442\u044c.\n
    \n
    \n\u0422\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b > \u0424\u043e\u0440\u043c\u0430\u0442\u044b \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb. \u042d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u0435\u0439 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0437\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u0438\u043c\u0435\u044e\u0449\u0438\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430.\n
    \n
    \n\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u00ab\u0421\u0435\u0439\u0447\u0430\u0441\u00bb \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0443\u0437\u043b\u0430.", "Text_src": "In the time field type, special characters in the format (all starting with \"%\") are replaced by elements of the data, similar to number fields. Press the \"Format Help\" button from the field format dialog for formatting details. Non-special characters will be output as themselves.
    \n
    \nThere is also an edit format under \"Tools > General Options > Data Editor Formats\". This controls how time fields are displayed in the Data Editor view. Generally, entries in the data editor with various formats will be correctly interpreted regardless of this setting.
    \n
    \nA default initial field value of \"Now\" can be used to enter the time of node creation." }, "format": "HEAD_PARA", "uid": "f16ffd06a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0414\u0430\u0442\u0430 \u0438 \u0412\u0440\u0435\u043c\u044f", "Name_src": "DateTime Type", "Text": "\u041f\u043e\u043b\u044f \u00ab\u0414\u0430\u0442\u0430 \u0438 \u0412\u0440\u0435\u043c\u044f\u00bb \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u044e\u0442 \u0434\u0430\u0442\u0443 \u0438 \u0432\u0440\u0435\u043c\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u043b\u0435, \u0447\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u043c \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u0442\u043e\u043a \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0421\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f (\u0432\u0441\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u0441 \"%\") \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u0430\u043a \u0432 \u043f\u043e\u043b\u044f\u0445 \u0434\u0430\u0442\u044b \u0438 \u043f\u043e\u043b\u044f\u0445 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u0414\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0441\u0432\u0435\u0434\u0435\u043d\u0438\u0439 \u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0421\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e\u00bb \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438 \u043f\u043e\u043b\u044f. \u041d\u0435\u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0432\u044b\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0442\u0430\u043a\u0438\u043c\u0438, \u043a\u0430\u043a \u043e\u043d\u0438 \u0435\u0441\u0442\u044c.\n
    \n
    \n\u041f\u0440\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u043e\u043b\u0435\u0439 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u0442\u0438\u043f\u043e\u043c \u00ab\u0414\u0430\u0442\u0430 \u0438 \u0412\u0440\u0435\u043c\u044f\u00bb \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b > \u0424\u043e\u0440\u043c\u0430\u0442\u044b \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb. \u0417\u0430\u043f\u0438\u0441\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u043b\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u044b \u043f\u0440\u043e\u0431\u0435\u043b\u043e\u043c.\n
    \n
    \n\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u044f \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u00ab\u0421\u0435\u0439\u0447\u0430\u0441\u00bb \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0432\u0432\u043e\u0434\u0430 \u0434\u0430\u0442\u044b \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0443\u0437\u043b\u0430.", "Text_src": "The DateTime field combines dates and times into a single field that is useful for timestamps. Special characters in the format (all starting with \"%\") are replaced by elements of the data, as in date and time fields. Press the \"Format Help\" button from the field format dialog for formatting details. Non-special characters will be output as themselves.
    \n
    \nThe DateTime edit format is uses the date and time formats located in \"Tools > General Options > Data Editor Formats\". The date and time formats are combined, separated by a space character.
    \n
    \nA default initial field value of \"Now\" can be used to enter the date and time of node creation." }, "format": "HEAD_PARA", "uid": "f16ffe14a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0412\u044b\u0431\u043e\u0440", "Name_src": "Choice Type", "Text": "\u041f\u043e\u043b\u044f \u0441 \u0442\u0438\u043f\u043e\u043c \u0432\u044b\u0431\u043e\u0440 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0431\u0438\u0440\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0438\u0437 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043e\u043a\u043d\u0430 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430. \u0412 \u0441\u0442\u0440\u043e\u043a\u0430\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0442\u0438\u043f\u043e\u0432 \u043f\u0435\u0440\u0435\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u043c \u00ab/\u00bb (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u00ab//\u00bb, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0438\u043c\u0432\u043e\u043b \u00ab/\u00bb \u0432 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0435). \u0417\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0432\u044b\u0431\u043e\u0440\u0443, \u0432\u044b\u0437\u043e\u0432\u0443\u0442 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u043d\u0435\u0433\u043e \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432 \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u043b\u0435\u0432\u043e\u043c \u0443\u0433\u043b\u0443 \u043f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u044b \u043d\u0430 \u00ab#####\u00bb.", "Text_src": "The choice field type allows for the selection of text items from a pull-down edit list. The formatting strings for these types list the items separated with the \"/\" character (use \"//\" to get a literal \"/\" in an item). Entries in the data editor which do not match the choices will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with \"#####\"." }, "format": "HEAD_PARA", "uid": "f16fff18a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0410\u0432\u0442\u043e\u0412\u044b\u0431\u043e\u0440", "Name_src": "Auto Choice Type", "Text": "\u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u043f\u043e\u043b\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d \u0442\u0438\u043f\u0443 \u0432\u044b\u0431\u043e\u0440\u0430, \u043d\u043e \u0431\u0435\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0430. \u0417\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0438\u0437 \u0432\u0441\u0435\u0445 \u0440\u0430\u043d\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0412\u0441\u0435 \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0435 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.", "Text_src": "This field type is similar to the choice type, but without a format string. The entries in the pull-down menu are automatically generated from all previously used entries. Any entries that are typed will be available in the pull-down menu for future use. " }, "format": "HEAD_PARA", "uid": "f1700008a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f", "Name_src": "Combination Type", "Text": "\u041f\u043e \u0441\u0443\u0442\u0438, \u044d\u0442\u043e \u044d\u043a\u0432\u0438\u0432\u0430\u043b\u0435\u043d\u0442 \u0442\u0438\u043f\u0430 \u0432\u044b\u0431\u043e\u0440\u0430 \u0441 \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u0432\u044b\u0431\u043e\u0440\u043e\u043c [\u0438\u043d\u0430\u0447\u0435 \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432]. \u0417\u0430\u043f\u0438\u0441\u0438 \u0441\u0442\u0440\u043e\u043a\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u043c \u00ab/\u00bb. \u0412 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u043c\u0435\u043d\u044e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0444\u043b\u0430\u0436\u043a\u0438 [\u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u044e\u0449\u0438\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f] \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043c\u0435\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0443\u0437\u043b\u043e\u0432. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0432\u044b\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u0437\u0430\u043f\u044f\u0442\u0443\u044e \u0438 \u043f\u0440\u043e\u0431\u0435\u043b. \u042d\u0442\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0430 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u0430\u00bb \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0422\u0438\u043f\u044b \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u041d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435\u00bb, \u0447\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f [\u0420\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u0417\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0422\u0438\u043f\u0430 \u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f && \u0421\u043f\u0438\u0441\u043a\u043e\u0432 \u0414\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0423\u0437\u043b\u043e\u0432].", "Text_src": "This is basically the equivalent of the choice type with multiple selection. The formatting string entries are separated by the \"/\" character. The pull-down menu shows check-boxes that are checked for currently selected nodes. By default, the selected entries are output separated by a comma and a space. This can be changed in the \"Type Config\" tab of the \"Data > Configure Types Dialog\". Click the \"Show Advanced\" button to see the separator setting." }, "format": "HEAD_PARA", "uid": "f1700102a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0410\u0432\u0442\u043e\u041a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f", "Name_src": "Auto Combination Type", "Text": "\u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u043f\u043e\u043b\u044f \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u0435\u043d \u0442\u0438\u043f\u0443 \u043a\u043e\u043c\u0431\u0438\u043d\u0430\u0446\u0438\u044f, \u043d\u043e \u0431\u0435\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0430. \u0417\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0438\u0437 \u0432\u0441\u0435\u0445 \u0440\u0430\u043d\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u0438\u0441\u0435\u0439. \u0412\u0441\u0435 \u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0438\u0441\u0438 \u0431\u0443\u0434\u0443\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0432 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0435 \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f.", "Text_src": "This field type is similar to the combination type, but without a format string. The entries in the pull-down menu are automatically generated from all previously used entries. Any entries that are typed will be available in the pull-down menu for future use. " }, "format": "HEAD_PARA", "uid": "f1700206a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0412\u043d\u0435\u0448\u043d\u044f\u044f \u0413\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0430", "Name_src": "External Link Type", "Text": "\u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044b \u0441\u0441\u044b\u043b\u043e\u043a, \u0432\u043a\u043b\u044e\u0447\u0430\u044f http \u0438 https \u0434\u043b\u044f \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446, mailto \u0434\u043b\u044f \u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b \u0438 file \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u043e\u0432. \u0412\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u0435 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0442\u0438\u043f \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0432\u0432\u0435\u0441\u0442\u0438 \u0430\u0434\u0440\u0435\u0441 \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0435 \u0438\u043c\u044f \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438. \u0412 \u043f\u043e\u043b\u044f\u0445 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0435 \u0438\u043c\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u0432 [\u0441\u043a\u043e\u0431\u043a\u0430\u0445] \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438 \u0432 \u043e\u043a\u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0430. \u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u00abfile\u00bb \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043a\u043d\u043e\u043f\u043a\u0443 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u043f\u0443\u0442\u0438 \u0438 \u043a\u043d\u043e\u043f\u043a\u0438 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e\u0433\u043e \u0438\u043b\u0438 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043f\u0443\u0442\u0438.\n
    \n
    \n\u0415\u0441\u043b\u0438 \u0449\u0435\u043b\u043a\u043d\u0443\u0442\u044c \u043d\u0430 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0443 \u0432 \u043e\u043a\u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u0438\u043b\u0438 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u00ab\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0443\u00bb \u0438\u0437 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0433\u043e \u043c\u0435\u043d\u044e, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0433\u043e \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438 \u0432 \u043f\u043e\u043b\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u0430 \u0432 \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 [\u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0444\u0430\u0439\u043b \u0432 Windows \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0430\u0441\u0441\u043e\u0446\u0438\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0441 \u0444\u0430\u0439\u043b\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c]. \u0412 Linux \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0441\u0440\u0435\u0434\u044b \u00abBROWSER\u00bb \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443 \u0442\u0438\u043f\u0430 \u00abmozilla% s\u00bb \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044e \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u043e\u0433\u043e \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430.", "Text_src": "This type can support various link protocols, including http and https for web pages, mailto for email addresses and file for local files. A pull down dialog in the data editor allows the selection of the protocol type and the entry of an address and a display name. In the edit boxes, the display name shows up in [brackets], and it is used as the text of the link in the output view. The \"file\" protocol also provides a button to browse for a path and buttons to choose either absolute or relative path names.
    \n
    \nClicking on the link in the output view or choosing \"Open Link\" from the right-click context menu in the edit box will open the link in a web browser. In Linux, setting the \"BROWSER\" environment variable to a string like \"mozilla %s\" will result in the desired browser being used." }, "format": "HEAD_PARA", "uid": "f1700300a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0412\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u044f\u044f \u0413\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0430", "Name_src": "Internal Link Type", "Text": "\u042d\u0442\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u044e\u0442 \u044f\u0440\u043b\u044b\u043a\u0438 \u0434\u043b\u044f \u0432\u044b\u0431\u043e\u0440\u0430 [\u0438 \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0430 \u043a] \u0443\u0437\u043b\u043e\u0432 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b. \u0427\u0442\u043e\u0431\u044b \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443, \u0449\u0435\u043b\u043a\u043d\u0438\u0442\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0443 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0438 \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0431\u0435\u0440\u0438\u0442\u0435 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0443\u0437\u0435\u043b \u0432 \u0434\u0435\u0440\u0435\u0432\u0435. \u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0435 \u0438\u043c\u044f \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u043e \u0432 \u043a\u0432\u0430\u0434\u0440\u0430\u0442\u043d\u044b\u0445 \u0441\u043a\u043e\u0431\u043a\u0430\u0445. \u0418\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0438\u043c\u0435\u043d\u0438 \u044f\u0440\u043b\u044b\u043a\u0430 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438, \u043d\u043e \u043e\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043e. \u041a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u043d\u043e\u0435 \u043c\u0435\u043d\u044e, \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c\u043e\u0435 \u043f\u0440\u0430\u0432\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u043e\u0439 \u043c\u044b\u0448\u0438, \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043b\u044f \u043e\u0447\u0438\u0441\u0442\u043a\u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u0438\u043b\u0438 \u0432\u044b\u0431\u043e\u0440\u0430 \u0446\u0435\u043b\u0435\u0432\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \n
    \n
    \n\u0429\u0435\u043b\u0447\u043e\u043a \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432 \u043e\u043a\u043d\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u0432\u044b\u0431\u0435\u0440\u0435\u0442 \u0446\u0435\u043b\u0435\u0432\u043e\u0439 \u0443\u0437\u0435\u043b \u0432 \u0434\u0435\u0440\u0435\u0432\u0435.", "Text_src": "These links create shortcuts to select nodes elsewhere in the tree structure. To create a link, click the pull-down arrow and then select the target node in the tree view. The display name is shown in brackets. It is initially set to the target node title, but it can be edited. The right-click context menu can be used to clear the link or to select the target node.
    \n
    \nClicking the link in the output view will select the target node in the tree view." }, "format": "HEAD_PARA", "uid": "f1700404a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0418\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435", "Name_src": "Picture Type", "Text": "\u042d\u0442\u0438 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0438 \u0441\u043b\u0443\u0436\u0430\u0442 \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0432 \u043e\u043a\u043d\u043e \u0432\u044b\u0432\u043e\u0434\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u043d\u0438 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442. \u0412 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043a\u043d\u043e\u043f\u043a\u0430 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c [\u0441 \u0443\u0437\u043b\u043e\u043c]. \u0412 \u043e\u043a\u043d\u0435 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u044b\u0435 \u0438\u043b\u0438 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0443\u0442\u0438 \u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f.", "Text_src": "These links add referenced pictures to the output view. A pull down dialog in the data editor has a button to browse for picture files to be linked. It also allows absolute or relative paths to be used and has a small image preview." }, "format": "HEAD_PARA", "uid": "f17004fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0422\u0438\u043f", "Name_src": "Math Type", "Text": "\u0422\u0438\u043f\u044b \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u043f\u0443\u0442\u0435\u043c \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439. \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044f, \u043f\u043e\u043b\u044f \u0434\u0430\u0442, \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435, \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u043f\u043e\u043b\u044f \u0438 / \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e\u043b\u044f. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 [\u0438\u043d\u0430\u0447\u0435 \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435], \u0440\u0435\u043b\u044f\u0446\u0438\u043e\u043d\u043d\u044b\u0435 [\u0438\u043d\u0430\u0447\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f] \u0438 \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u044b\u0435 [\u0438\u043d\u0430\u0447\u0435 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435] \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b. \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u043c\u0438 \u043c\u043e\u0433\u0443\u0442 \u044f\u0432\u043b\u044f\u0442\u044c\u0441\u044f \u0447\u0438\u0441\u043b\u0430, \u0442\u0435\u043a\u0441\u0442, \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0434\u0430\u0442\u044b \u0438\u043b\u0438 \u0432\u0440\u0435\u043c\u044f.\n
    \n
    \n\u0427\u0442\u043e\u0431\u044b \u0437\u0430\u0434\u0430\u0442\u044c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043f\u043e\u043b\u044f, \u043d\u0430\u0436\u043c\u0438\u0442\u0435 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u0417\u0430\u0434\u0430\u0442\u044c \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435\u00bb \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043b\u044f\u00bb \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0422\u0438\u043f\u044b \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u041e\u0442\u043a\u0440\u043e\u0435\u0442\u0441\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 \u0434\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043d\u0430 \u043d\u0438\u0445 \u0441\u0441\u044b\u043b\u043e\u043a \u0441\u043b\u0435\u0432\u0430 \u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0439 \u0441\u043f\u0440\u0430\u0432\u0430. \u0412\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u00ab\u0423\u0440\u043e\u0432\u0435\u043d\u044c \u0441\u0441\u044b\u043b\u043a\u0438\u00bb \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0441\u044b\u043b\u043a\u0438 \u2014 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u044f\u0442 \u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0436\u0435 [\u0441\u0432\u043e\u0435\u0433\u043e] \u0443\u0437\u043b\u0430, \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e, \u043a\u043e\u0440\u043d\u0435\u0432\u043e\u0433\u043e \u0438\u043b\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0435\u0433\u043e \u0443\u0437\u043b\u0430. \u0412\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u0435 \u043c\u0435\u043d\u044e \u00ab\u0422\u0438\u043f \u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430\u00bb \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432 \u0432\u0438\u0434\u0435 \u0434\u0430\u0442\u044b, \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0438\u043b\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b. \u0412\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u0435 \u043c\u0435\u043d\u044e \u00ab\u0422\u0438\u043f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u00bb \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b, \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0438\u043b\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b. \u041a\u043d\u043e\u043f\u043a\u0438 \u0441\u043e \u0441\u0442\u0440\u0435\u043b\u043a\u043e\u0439 \u0432\u043d\u0438\u0437 \u043f\u043e\u0434 \u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u044e\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043a \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0449\u0435\u0439\u0441\u044f \u043d\u0438\u0436\u0435. \u0427\u0430\u0441\u0442\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u0432\u0435\u0434\u0435\u043d\u044b \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f.\n
    \n
    \n\u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0442\u0430\u043a\u0443\u044e \u200b\u200b\u043a\u0430\u043a sum, max, min, mean \u0438\u043b\u0438 join. \u041c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u043e\u043b\u0435 \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u0435\u0439 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u0438\u043b\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432, \u043d\u043e \u043d\u0435 \u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043f\u043e\u043b\u044f \u0443\u0437\u043b\u043e\u0432 \u0441\u0432\u043e\u0435\u0433\u043e \u0436\u0435 \u0443\u0440\u043e\u0432\u043d\u044f [\u0438\u043d\u0430\u0447\u0435 \u0441\u0435\u0441\u0442\u0440\u0438\u043d\u0441\u043a\u0438\u0435 \u0443\u0437\u043b\u044b] \u043d\u0430 \u0441\u0435\u0431\u044f (\u0446\u0438\u043a\u043b\u0438\u0447\u0435\u0441\u043a\u0443\u044e \u0441\u0441\u044b\u043b\u043a\u0443). \u0421\u0441\u044b\u043b\u043a\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u043c\u044f \u043f\u043e\u043b\u044f, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u043d\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u043f\u043e\u043b\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438\u043b\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432 \u0441 \u0442\u0430\u043a\u0438\u043c \u0438\u043c\u0435\u043d\u0435\u043c, \u0434\u0430\u0436\u0435 \u0435\u0441\u043b\u0438 \u044d\u0442\u043e \u0443\u0437\u0435\u043b \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0442\u0438\u043f\u0430.\n
    \n
    \n\u0412 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439 \u0442\u0438\u043f\u0430 \u00ab\u0414\u0430\u0442\u0430\u00bb \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0434\u043d\u0435\u0439, \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0441 1 \u044f\u043d\u0432\u0430\u0440\u044f 1970 \u0433., \u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043f\u043e\u043b\u0435\u0439 \u00ab\u0412\u0440\u0435\u043c\u044f\u00bb \u2014 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u0441\u0435\u043a\u0443\u043d\u0434 \u043f\u043e\u0441\u043b\u0435 \u043f\u043e\u043b\u0443\u043d\u043e\u0447\u0438. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043f\u043e\u043b\u044f \u0434\u0430\u0442 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0447\u0438\u0442\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0434\u043d\u0435\u0439, \u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u043d\u0435\u0439 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043b\u0438 \u0432\u044b\u0447\u0438\u0442\u0430\u0442\u044c \u0438\u0437 \u0434\u0430\u0442, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u0434\u0430\u0442\u044b. \u041f\u043e\u043b\u044f \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0447\u0438\u0442\u0430\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0448\u0435\u0434\u0448\u0438\u0445 \u0441\u0435\u043a\u0443\u043d\u0434, \u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0435\u043a\u0443\u043d\u0434 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u043b\u0438 \u0432\u044b\u0447\u0438\u0442\u0430\u0442\u044c \u0438\u0437 \u0432\u0440\u0435\u043c\u0435\u043d\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u0432\u0440\u0435\u043c\u044f. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0439 \u0434\u0430\u0442\u044b \u0438 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432\u0432\u0435\u0434\u0435\u043d\u044b \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u0438\u043c\u0435\u043d\u0430 \u043f\u043e\u043b\u0435\u0439 ({* Now_Date *}, {* Now_Time *} \u0438 {* Now_Date_Time *}). \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0421\u0441\u044b\u043b\u043a\u0438\u00bb \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0441\u0441\u044b\u043b\u043e\u043a, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438.\n
    \n
    \n\u041e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 [\u0438\u0437 \u0433\u0440\u0443\u043f\u043f\u044b \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432] \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u00abif\u00bb \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442, \u0437\u0430\u0432\u0438\u0441\u044f\u0449\u0438\u0439 \u043e\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u043f\u043e\u043b\u044f. \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u00ab\u0438\u0441\u0442\u0438\u043d\u043d\u043e\u0435_\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435, \u0435\u0441\u043b\u0438 \u0443\u0441\u043b\u043e\u0432\u0438\u0435, \u0432 \u043f\u0440\u043e\u0442\u0438\u0432\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043b\u043e\u0436\u043d\u043e\u0435_\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u00bb. \u0421\u0430\u043c\u043e \u0441\u043e\u0431\u043e\u0439 \u0440\u0430\u0437\u0443\u043c\u0435\u0435\u0442\u0441\u044f, \u0441\u0442\u0440\u043e\u043a\u0438 \u00ab\u0438\u0441\u0442\u0438\u043d\u043d\u043e\u0435_\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u00bb, \u00ab\u0443\u0441\u043b\u043e\u0432\u0438\u0435\u00bb \u0438 \u00ab\u043b\u043e\u0436\u043d\u043e\u0435_\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u00bb \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u044b\u0442\u044c \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u044b \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u043c\u0438 \u043f\u043e\u043b\u044f\u043c\u0438 \u0438\u043b\u0438 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0432\u0441\u0442\u0430\u0432\u043b\u0435\u043d \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 (\u043f\u0440\u0438 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0438), \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0441\u043a\u043e\u0431\u043a\u0438 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u0437\u0438\u0446\u0438\u0439 \u0434\u043b\u044f \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f. \u042d\u0442\u0438 \u043a\u0440\u0443\u0433\u043b\u044b\u0435 \u0441\u043a\u043e\u0431\u043a\u0438 \u043d\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0432 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f\u0445.\n
    \n
    \n\u0422\u0435\u043a\u0441\u0442\u043e\u0432\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u00abjoin\u00bb \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0434\u0440\u0443\u0433\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 (\u0438\u043b\u0438 \u0438\u0437 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432). \u041f\u0435\u0440\u0432\u044b\u0439 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u2014 \u044d\u0442\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c\u043d\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u043c\u0435\u0436\u0434\u0443 \u043a\u0430\u0436\u0434\u044b\u043c \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u043e\u043c \u0442\u0435\u043a\u0441\u0442\u0430. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b \u2014 \u044d\u0442\u043e \u0442\u0435\u043a\u0441\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0443\u0436\u043d\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c.\n
    \n
    \n\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u043a\u043d\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u043e \u043e\u043d\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f. \u0427\u0442\u043e\u0431\u044b \u0441\u043a\u0440\u044b\u0442\u044c \u0438\u0445, \u0441\u043d\u0438\u043c\u0438\u0442\u0435 \u0444\u043b\u0430\u0436\u043e\u043a \u00ab\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u043e\u043b\u044f \u0432 \u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b > \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u00bb.\n
    \n
    \n\u0422\u0430\u043a\u0436\u0435 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0424\u0430\u0439\u043b > \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u0443\u0441\u0442\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u043a\u0430\u043a \u043d\u043e\u043b\u0435\u0439. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0444\u043b\u0430\u0436\u043e\u043a \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d (\u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e), \u043f\u0443\u0441\u0442\u043e\u0435 \u043f\u043e\u043b\u0435, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0441\u0441\u044b\u043b\u0430\u0435\u0442\u0441\u044f \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0435 \u043f\u043e\u043b\u0435, \u0438\u043c\u0435\u0435\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u043e\u043b\u044c (\u0434\u043b\u044f \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439) \u0438\u043b\u0438 \u043f\u0443\u0441\u0442\u043e\u0435 (\u0434\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439). \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u0444\u043b\u0430\u0436\u043e\u043a \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d, \u043b\u044e\u0431\u044b\u0435 \u043f\u0443\u0441\u0442\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 [\u043d\u0430 \u043d\u0435\u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044f] \u0442\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0443\u0442 \u043a \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442, \u0431\u0443\u0434\u0443\u0442 \u043f\u0443\u0441\u0442\u044b\u043c\u0438.\n
    ", "Text_src": "Math field types are configured by defining equations. The equations can reference number fields, date fields, time fields, boolean fields, text fields and/or other math fields. The resulting values of math fields are automatically calculated for each node. Various mathematical, relational and string operators are available. The results can be numbers, text, boolean, dates or times.\n
    \n
    \nTo define a math field equation, press the \"Define Equation\" button in the \"Field Config\" tab of the \"Data > Configure Types Dialog\". This brings up a dialog with fields to reference on the left and math operators on the right. The \"Reference Level\" pull-down determines whether the reference is from the same node, the node's parent, the root node, or the node's children. The \"Result Type\" pull-down allows arithmetic, date, time, boolean or text results to be chosen. The \"Operator Type\" pull-down allows numeric, comparison or text operators to be shown in the operator list. The down-arrow buttons below the references and operators add the selected item to the equation text below. Portions of equations can also be typed directly in the equation text line editor.\n
    \n
    \nReferences to child nodes must be enclosed in a grouping function, such as sum, max, min, mean or join. A math field can contain a parent or child reference to itself, but not a same-level reference to itself (a circular reference). The references only contain the field name, so they will reference a parent or child field with that name even if it is a different node type.\n
    \n
    \nIn equations, date fields are represented by the number of days since January 1, 1970, and time fields are the number of seconds since midnight. So date fields can be subtracted to give the number of days elapsed, and numbers of days can be added to or subtracted from dates to result in new dates. Time fields can be subtracted to give the number of seconds elapsed, and numbers of seconds can be added to or subtracted from times to result in new times. \nAlso, special field names ({*Now_Date*}, {*Now_Time*} and {*Now_Date_Time*}) can be manually typed in equations to represent current dates and times. The \"Data->Regenerate References\" command may be needed to force re-evaluation of time-based references.\n
    \n
    \nThe \"if\" comparison operator can be used to make the result depend on the value of another field. The expression is written as \"true_value if condition else false_value\". Of course, the \"true_value\", \"condition\" and \"false_value\" strings must be replaced with valid fields or expressions. If this operator is inserted from the operator list (under comparisons), it will include parenthesis as placeholders. These parenthesis are optional in the equations.\n
    \n
    \nThe \"join\" text function is used to combine text from several other fields (or from child nodes). The first argument to the function is a separator string that is placed between each piece of text. The remaining argument(s) are the text to be joined.\n
    \n
    By default, math fields are shown in the data edit view, but they are read-only. To hide them, uncheck the \"Show math fields in the Data Edit View\" box under \"Tools > General Options > Features Available\".\n
    \n
    \nThere is also an option under \"File > Properties\" that toggles whether blank fields are treated as zeros. If checked (the default), a blank field that is referenced by a math field has a value of zero (for numeric operations) or blank (for text operations). If unchecked, any blank references also cause equations that reference them to be blank.\n
    " }, "format": "HEAD_PARA", "uid": "f17005f8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u041d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044f", "Name_src": "Numbering Type", "Text": "\u042d\u0442\u043e\u0442 \u0442\u0438\u043f (\u043d\u0435 \u043f\u0443\u0442\u0430\u0442\u044c \u0441 \u0447\u0438\u0441\u043b\u043e\u0432\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u0432\u044b\u0448\u0435) \u0434\u0430\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044e\u00bb. \u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u0421\u043f\u0440\u0430\u0432\u043a\u0430 \u043f\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e\u00bb \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb (\u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043b\u044f\u00bb) \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0432\u044b\u0432\u043e\u0434\u0430. \u041e\u0434\u043d\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 [1\u2014i] \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0445\u0435\u043c\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 [\u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435]. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u00ab/\u00bb [1\u2014i./] \u0441\u043e\u0437\u0434\u0430\u0441\u0442 \u043c\u0430\u043a\u0435\u0442 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0438\u043f\u0430 \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044f\u043c\u0438 \u043d\u0430 \u0440\u0430\u0437\u043d\u044b\u0445 \u0443\u0440\u043e\u0432\u043d\u044f\u0445. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u0438\u043c\u0432\u043e\u043b\u0430 \".\" \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044c \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u043c\u0430\u043a\u0435\u0442\u0443 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0442\u0438\u043f\u0430 \"2.3.5\". \n
    \n
    \n\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u043e\u043b\u044f \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438, \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043e\u043d\u0438 \u043d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u043a\u043d\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u0427\u0442\u043e\u0431\u044b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438\u0445 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0434\u043b\u044f \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 \u0444\u043b\u0430\u0436\u043e\u043a \u00ab\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044f \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b > \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438\u00bb. \u041a\u043e\u0433\u0434\u0430 \u043e\u043d\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u043a\u043d\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u043d\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u0441\u0442\u0438\u043b\u0435 [\u0447\u0438\u0441\u043b\u043e\u0432\u043e\u0439] \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432, \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0432\u044b\u0432\u043e\u0434\u0430.", "Text_src": "This type (not to be confused with the number type above) provides fields that are automatically filled in with the \"Data > Update Numbering\" command. The \"Format Help\" button in the field format dialog shows the output format options. A single format level will result in a simple sequential numbering scheme. Use of the \"/\" level separator will result in an outline-type numbering with different sequences at different levels. Use of the \".\" section separator will result in a \"2.3.5\" type numbering scheme.\n
    \n
    \nSince numbering fields are automatically populated, by default they are not shown in the data edit view. To show them, check the \"Show numbering fields in the Data Edit View\" box under \"Tools > General Options > Features Available\". When they are shown in the data edit view, they show up in section numbering style, regardless of the output format." }, "format": "HEAD_PARA", "uid": "f1700710a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0438\u043f \u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0412\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435", "Name_src": "Regular Expression Type", "Text": "\u042d\u0442\u043e\u0442 \u0442\u0438\u043f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 [\u0432\u0432\u043e\u0434\u0438\u043c\u044b\u0445] \u0441\u0442\u0440\u043e\u043a \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u044c\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0442\u0430\u043a, \u0447\u0442\u043e [\u0432\u0432\u0435\u0434\u0435\u043d\u043d\u044b\u0435] \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c\u0438 \u043f\u0440\u0435\u0434\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c [\u0432 \u043f\u043e\u043b\u0435 \u00ab\u0424\u043e\u0440\u043c\u0430\u0442 \u0412\u044b\u0432\u043e\u0434\u0430\u00bb \u0432\u043a\u043b\u0430\u0434\u043a\u0438 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u041f\u043e\u043b\u044f\u00bb \u043e\u043a\u043d\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0422\u0438\u043f\u044b \u0414\u0430\u043d\u043d\u044b\u0445\u00bb]. \u0414\u043b\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0432\u0432\u043e\u0434\u0430 \u043f\u043e\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 Python. \u0417\u0430\u043f\u0438\u0441\u0438 \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044e \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438, \u0432\u044b\u0437\u043e\u0432\u0443\u0442 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u0438\u043d\u0435\u0433\u043e \u0442\u0440\u0435\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a\u0430 \u0432 \u0432\u0435\u0440\u0445\u043d\u0435\u043c \u043b\u0435\u0432\u043e\u043c \u0443\u0433\u043b\u0443 \u043f\u043e\u043b\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0431\u0443\u0434\u0443\u0442 \u0437\u0430\u043c\u0435\u043d\u0435\u043d\u044b \u043d\u0430 \u00ab#####\u00bb.", "Text_src": "This type allows arbitrary format strings to be matched that restrict the data to a particular format. It uses Python regular expression syntax. Entries in the data editor which do not match the format string expression will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with \"#####\"." }, "format": "HEAD_PARA", "uid": "f170081ea25a11e7b7c67054d2175f18" }, { "children": [ "f1700a26a25a11e7b7c67054d2175f18", "f1700b34a25a11e7b7c67054d2175f18", "f1700c38a25a11e7b7c67054d2175f18", "f1700d3ca25a11e7b7c67054d2175f18", "f1700e40a25a11e7b7c67054d2175f18", "bbbf735ac24711e8b560d66a6ab671cb" ], "data": { "Name": "\u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0412\u044b\u0432\u043e\u0434\u0430 \u0432 \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0441\u0442\u044f\u0445", "Name_src": "Output Formatting Details" }, "format": "HEADINGS", "uid": "f1700936a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u0424\u043e\u0440\u043c\u0430\u0442\u0430 \u0412\u044b\u0432\u043e\u0434\u0430", "Name_src": "Output Format Examples", "Text": "\u042d\u0442\u043e \u043f\u0440\u0438\u043c\u0435\u0440 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0432\u044b\u0432\u043e\u0434\u0430 \u0434\u043b\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u043a\u043d\u0438\u0433:
    \n
    \n\"{*Title*}\"
    \n(c) {*Copyright*}, Rating: {*Rating*}
    \n{*PlotDescription*}
    \n
    \n\u0418\u043c\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u0437\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u043e \u0432 \u0444\u0438\u0433\u0443\u0440\u043d\u044b\u0435 \u0441\u043a\u043e\u0431\u043a\u0438 \u0438 \u0437\u0432\u0435\u0437\u0434\u043e\u0447\u043a\u0438: {* *}. \u0417\u0430 \u0431\u043e\u043b\u044c\u0448\u0438\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u0444\u0430\u0439\u043b\u0430\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u044b \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0438\u0437 \u043c\u0435\u043d\u044e \u00ab\u0424\u0430\u0439\u043b > \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u041f\u0440\u0438\u043c\u0435\u0440\u00bb.", "Text_src": "Here is an example of output formatting for a book list:
    \n
    \n\"{*Title*}\"
    \n(c) {*Copyright*}, Rating: {*Rating*}
    \n{*PlotDescription*}
    \n
    \nEach of the field names in enclosed in {* *}, curly brackets and asterisks. For more examples, see the sample files that can be opened using the \"File > Open Sample\" command." }, "format": "HEAD_PARA", "uid": "f1700a26a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0424\u043e\u0440\u043c\u0430\u0442\u044b \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430", "Name_src": "Title Formats", "Text": "\u041a\u043e\u0433\u0434\u0430 \u0443\u0437\u0435\u043b \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0435\u0442\u0441\u044f, \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u044b\u0442\u0430\u0435\u0442\u0441\u044f \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0448\u0430\u0431\u043b\u043e\u043d \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430, \u0447\u0442\u043e\u0431\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u043e\u043b\u044f (\u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0435 \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u0440\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0441\u0442\u0440\u043e\u043a \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432\u00bb). \u0415\u0441\u043b\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u043e\u0435, \u043e\u043d\u043e \u043c\u043e\u0436\u0435\u0442 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0447\u0438\u0442\u0430\u0442\u044c \u0436\u0435\u043b\u0430\u0435\u043c\u044b\u0439 \u0432\u044b\u0432\u043e\u0434. \u0421\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u0442\u0430\u043a\u0438\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439, \u043a\u0430\u043a \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0441\u043c\u0435\u0436\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439 \u0431\u0435\u0437 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u0440\u0430\u0437\u0434\u0435\u043b\u044f\u044e\u0449\u0438\u0445 \u0438\u0445, \u0435\u0441\u043b\u0438 \u0432\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u0430\u0442\u044c \u0443\u0437\u043b\u044b \u0432 \u0434\u0435\u0440\u0435\u0432\u0435.
    \n
    \n\u0415\u0441\u043b\u0438 \u0434\u043b\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a, \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430.", "Text_src": "When a node in the tree is renamed, the program attempts to match the title formatting pattern to set the appropriate fields (the same title matching occurs when editing lines in the \"Title List\" view). If the title formatting is too complex, it may not correctly guess the intent. Things like adjacent fields with no characters separating them should be avoided unless you do not wish to rename nodes from the tree.
    \n
    \nIf the text data used for a tree view title has multiple lines, only the first line will be used as the title." }, "format": "HEAD_PARA", "uid": "f1700b34a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u043c\u044b\u0435 \u0421\u0442\u0440\u043e\u043a\u0438 \u0412\u044b\u0432\u043e\u0434\u0430", "Name_src": "Skipped Output Lines", "Text": "\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u043f\u043e\u043b\u044f \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u0432\u044b\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0434\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u043f\u0443\u0441\u0442\u044b, \u0442\u043e \u044d\u0442\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 [\u043d\u0435 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0432\u044b\u0432\u043e\u0434\u0430] \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0432\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u043d\u0438 \u043f\u0443\u0441\u0442\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430, \u043d\u0438 \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442. \u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u044d\u0442\u043e \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0441\u0442\u0440\u043e\u043a\u0435 [\u0432\u044b\u0432\u043e\u0434\u0430] \u0431\u0435\u0437 \u043f\u043e\u043b\u0435\u0439 (\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442). \u0422\u0430\u043a\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0441\u0442\u0440\u043e\u043a\u0430 \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0442\u0435\u0433\u043e\u043c <br/> \u0438\u043b\u0438 <hr/>, \u044d\u0442\u043e\u0442 \u0442\u0435\u0433 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f, \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0439 \u0442\u0435\u0433 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f [\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0442\u0430\u043a\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u044d\u0442\u0438\u0445 \u0442\u0435\u0433\u043e\u0432 \u043d\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430].", "Text_src": "If all of the fields in an output format line are empty for a given node, then the line is skipped. No blank line or embedded text will be output for that line. Note that this does not apply to a line without any fields (only embedded text). Also, when a line ending with a <br/> or an <hr/> tag is skipped, the ending tag is retained." }, "format": "HEAD_PARA", "uid": "f1700c38a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0422\u0435\u0433\u0438 HTML", "Name_src": "HTML Tags", "Text": "\u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u00ab\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0442\u044c \u0442\u0435\u0433\u0438 HTML\u00bb \u043d\u0435 \u0432\u044b\u0431\u0440\u0430\u043d \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u0430\u00bb \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043b\u044e\u0431\u044b\u0435 HTML-\u0442\u0435\u0433\u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0435\u043a\u0441\u0442. \u0415\u0441\u043b\u0438 \u044d\u0442\u043e\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d, \u043f\u0440\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0432\u044b\u0432\u043e\u0434\u0430 \u0443\u0437\u043b\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u044b\u0435 \u0442\u0435\u0433\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f HTML.\n
    \n
    \n\u0427\u0430\u0441\u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u043c\u0438 \u0442\u0435\u0433\u0430\u043c\u0438 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \"<b> \u0436\u0438\u0440\u043d\u044b\u0439 </b>\", \"<u> \u043f\u043e\u0434\u0447\u0435\u0440\u043a\u0438\u0432\u0430\u043d\u0438\u0435 </u>\", \"\u0440\u0430\u0437\u0440\u044b\u0432 \u0441\u0442\u0440\u043e\u043a\u0438 <br/>\", \"\u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0430\u044f \u043b\u0438\u043d\u0438\u044f <hr/>\" \u0438 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0442\u0435\u0433\u0438 \u0448\u0440\u0438\u0444\u0442\u043e\u0432. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0438\u0437\u0431\u0435\u0433\u0430\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0431\u043b\u043e\u0447\u043d\u044b\u0445 \u0442\u0435\u0433\u043e\u0432.", "Text_src": "By default, the \"Allow HTML rich text in formats\" option is unchecked in the \"Type Config\" tab of the Configure Types Dialog. So any HTML tags are treated as plain text. If the option is enabled, simple HTML formatting tags can be used in node output formats.
    \n
    \nCommonly used tags include \"<b>bold</b>\", \"<u>underline</u>\", \"line break<br/>\", \"horizontal line<hr/>\", and various font tags. Complex block tags should generally be avoided." }, "format": "HEAD_PARA", "uid": "f1700d3ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0414\u0440\u0443\u0433\u0438\u0435 \u041f\u043e\u043b\u044f", "Name_src": "Other Field References", "Text": "\u041a \u0432\u044b\u0432\u043e\u0434\u0443 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0432 \u0443\u0437\u043b\u0435. \u041d\u0430\u0436\u0430\u0442\u0438\u0435 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 \u00ab\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u00bb \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0412\u044b\u0432\u043e\u0434\u00bb \u0432 \u0444\u043e\u0440\u043c\u0435 \u0435\u0433\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u0435\u043b\u0430\u0435\u0442 \u0432\u0438\u0434\u0438\u043c\u044b\u043c \u0432\u044b\u0431\u043e\u0440 \u0443\u0440\u043e\u0432\u043d\u044f \u0441\u0441\u044b\u043b\u043a\u0438.\n
    \n
    \n\u0415\u0441\u043b\u0438 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0441\u0441\u044b\u043b\u043a\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d \u043d\u0430 \u00abFile Info Reference\u00bb [\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0444\u0430\u0439\u043b\u0435], \u043a \u0432\u044b\u0432\u043e\u0434\u0443 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u043e\u043b\u044f, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0435 \u043c\u0435\u0442\u0430\u0434\u0430\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u0430. \u041a \u043d\u0438\u043c \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f File_Name [\u0418\u043c\u044f_\u0424\u0430\u0439\u043b\u0430], File_Path [\u041f\u0443\u0442\u044c_\u043a_\u0424\u0430\u0439\u043b\u0443], File_Size [\u0420\u0430\u0437\u043c\u0435\u0440_\u0424\u0430\u0439\u043b\u0430], File_ Mod_Date [\u0414\u0430\u0442\u0430_\u041c\u043e\u0434_\u0424\u0430\u0439\u043b\u0430] \u0438 File_ Mod_Time [\u0412\u0440\u0435\u043c\u044f_\u041c\u043e\u0434_\u0424\u0430\u0439\u043b\u0430]. \u042d\u0442\u0438 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a \"{*! Field_name *}\" \u0432 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u0430.\n
    \n
    \n\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f \u0434\u043b\u044f Any Ancestor Reference [\u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432-\u043f\u0440\u0435\u0434\u043a\u043e\u0432] (Parent Reference [\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u0420\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0443\u0437\u0435\u043b], Grandparent Reference [\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u041f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0443\u0437\u0435\u043b] \u0438 Great Grandparent Reference [\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u041f\u0440\u0430\u041f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u0443\u0437\u0435\u043b]). \u0414\u043b\u044f \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0441\u044b\u043b\u043a\u0438. \u041f\u0440\u0438 \u0435\u0433\u043e \u0432\u044b\u0431\u043e\u0440\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0442\u0441\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0438\u043c\u0435\u043d\u0430 \u043f\u043e\u043b\u0435\u0439, \u043d\u043e \u0432 \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0431\u0443\u0434\u0443\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u0434\u0430\u043d\u043d\u044b\u0435 \u043b\u044e\u0431\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0438\u043c\u0435\u043d\u0435\u043c \u043f\u043e\u043b\u044f. \u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u043e\u043b\u044f \u0438\u0437 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0443\u0437\u043b\u043e\u0432 \u0438 \u0443\u0437\u043b\u043e\u0432-\u043f\u0440\u0430\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u0439 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a \"{** field_name *}\" \u0438 \"{*** field_name *}\" \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0442\u0430\u043a\u0436\u0435 \u043e\u0431\u0449\u0438\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u043f\u0440\u0435\u0434\u043a\u043e\u0432, \u043f\u043e\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0435 \u043a\u0430\u043a \"{*? Field_name *}\", \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0435\u0440\u0443\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442 \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u043a\u0430 \u0441 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u043f\u043e\u043b\u0435\u043c. \n
    \n
    \n\u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u044b Child Reference [\u0421\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0443\u0437\u043b\u044b], \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0435\u0441\u044f \u043a\u0430\u043a \u00ab{* & amp; field_name *}\u00bb. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u0442\u0438\u043f \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432 \u0432\u044b\u0432\u043e\u0434 [\u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432] \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0443\u0437\u043b\u043e\u0432. \u0414\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u043e\u0442\u0434\u0435\u043b\u044f\u044e\u0442\u0441\u044f \u0441\u0442\u0440\u043e\u043a\u043e\u0439-\u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0435\u043c, \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u043e\u0439 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u0430\u00bb (\u043f\u0440\u0438 \u0430\u043a\u0442\u0438\u0432\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u043d\u043e\u043c \u043f\u043e\u043a\u0430\u0437\u0435 \u0444\u043e\u0440\u043c\u044b [\u043d\u0430\u0436\u0430\u0442\u043e\u0439 \u043a\u043d\u043e\u043f\u043a\u0435 \u00ab\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u00bb]). \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u044f\u0442\u0430\u044f \u0438 \u043f\u0440\u043e\u0431\u0435\u043b, \u043d\u043e \u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0430 <br/> \u0438\u043b\u0438 \u0447\u0442\u043e-\u043d\u0438\u0431\u0443\u0434\u044c \u0435\u0449\u0435.\n
    \n
    \n\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u00ab\u041f\u043e\u0434\u0441\u0447\u0435\u0442 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432\u00bb [Child Count]. \u0412 \u044d\u0442\u043e\u043c \u043f\u043e\u043b\u0435 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (\u043f\u043e\u043b\u0435 \u00abLevel1\u00bb [\u0423\u0440\u043e\u0432\u0435\u043d\u044c1]), \u0432\u043d\u0443\u043a\u043e\u0432 (\u043f\u043e\u043b\u0435 \u00abLevel2\u00bb [\u0423\u0440\u043e\u0432\u0435\u043d\u044c2]) \u0438\u043b\u0438 \u043f\u0440\u0430\u0432\u043d\u0443\u043a\u043e\u0432 (\u043f\u043e\u043b\u0435 \u00abLevel3\u00bb [\u0423\u0440\u043e\u0432\u0435\u043d\u044c3]) \u0443\u0437\u043b\u0430. \u0412 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u043e\u043d\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u043a\u0430\u043a {* # Level1 *}.
    \n
    \n\u041f\u0440\u0438\u043c\u0435\u0440\u044b \u044d\u0442\u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u0441\u043c. \u0432 \u0444\u0430\u0439\u043b\u0435 \u00absample_other_fields\u00bb (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0424\u0430\u0439\u043b > \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u041f\u0440\u0438\u043c\u0435\u0440\u00bb).", "Text_src": "References to fields that are not contained within the node can be added to the output. Pushing the \"Show Advanced\" button on the \"Output\" tab of the configure dialog makes a reference level selection become visible.
    \n
    \nIf the reference level is changed to \"File Info Reference\", fields containing file meta-data can be added to the output. These include the file name, path, size, modified date and modified time. These special fields are shown as \"{*!field_name*}\" in the title and output format editors.
    \n
    \nThere are field references to various ancestor nodes (parents, grandparents, etc.). These require the data type of the reference to be specified. This selection determines the field names that are available, but the data from any type with a matching field name will be shown in the output. References to fields from parent and grandparent nodes are shown as \"{**field_name*}\" and \"{***field_name*}\", respectively. There are also general ancestor references, shown as \"{*?field_name*}\", that take data from the closest ancestor with a matching field.
    \n
    \nReferences to child nodes can also be added, shown as \"{*&field_name*}\". These also require that the child data type be specified. The child data becomes embedded in the parent output. The child data is delimited with a separator string defined on the \"Type Config\" tab (with show advanced active). The separator defaults to a comma and a space, but can be set to <br/> or anything else.
    \n
    \nFinally, a \"Child Count\" reference can be added. This field will show the number of children (\"Level1\" field) or grandchildren (\"Level2\" field) of a node. These are shown as {*#Level1*} in the format editors.
    \n
    \nFor examples of these fields, see the \"sample_other_fields\" file (by using the \"File > Open Sample\" command)." }, "format": "HEAD_PARA", "uid": "f1700e40a25a11e7b7c67054d2175f18" }, { "children": [ "f1701156a25a11e7b7c67054d2175f18", "f170125aa25a11e7b7c67054d2175f18", "f1701368a25a11e7b7c67054d2175f18", "aa6f6ca4bb0711e7bbf43417ebd53aeb" ], "data": { "Name": "\u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0422\u0438\u043f\u043e\u0432 \u0432 \u0414\u0435\u0442\u0430\u043b\u044f\u0445", "Name_src": "Type Format Details" }, "format": "HEADINGS", "uid": "f1700f58a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u0431\u0449\u0438\u0435 \u0438 \u041f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u0435 \u0422\u0438\u043f\u044b", "Name_src": "Generic and Derived Types", "Text": "\u0422\u0438\u043f\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0445 \u043f\u043e\u043b\u0435\u0439 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u043e\u0442 \u043e\u0431\u0449\u0435\u0433\u043e \u0442\u0438\u043f\u0430. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0442\u0438\u043f\u0430\u043c \u0441 \u0440\u0430\u0437\u043d\u044b\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u044b\u0432\u043e\u0434\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u0438 \u0442\u043e\u0442 \u0436\u0435 \u043d\u0430\u0431\u043e\u0440 \u043f\u043e\u043b\u0435\u0439. \u041b\u044e\u0431\u044b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0435 \u043f\u043e\u043b\u0435\u0439 \u0438 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u043b\u0435\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043e\u0442\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u044f\u0445 \u0432\u0441\u0435\u0445 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432. \u042d\u0442\u043e \u043d\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u043e\u043b\u044f, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u043e-\u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u043e \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e.\n
    \n
    \n\u0415\u0441\u0442\u044c \u0434\u0432\u0430 \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432. \u0412\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0442\u0438\u043f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u043c, \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043f\u0440\u0438 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u0442\u0438\u043f\u0430 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u0442\u0438\u043f\u043e\u0432\u00bb \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb. \u041f\u043e-\u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u0442\u043e, \u0447\u0442\u043e \u0442\u0438\u043f \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u043c, \u043c\u043e\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u0430\u00bb \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 [\u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435] \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430, \u0435\u0441\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u043e\u043a\u0430\u0437\u0430\u043d \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a.", "Text_src": "Data types can be set to derive their field settings from a generic type. This allows types with different output formatting to always use the same set of fields. Any changes to the generic's list of fields and field types are automatically reflected in the fields of all derived types. This does not apply to a field's output formatting, which can still be set independently.
    \n
    \nThere are two methods for creating derived types. First, a derived option can be selected when copying a type on the \"Type List\" tab of the \"Data > Configure Types Dialog\". Alternately, a generic type can be specified from the derived type's \"Type Config\" tab of the dialog if the advanced functions are shown." }, "format": "HEAD_PARA", "uid": "f1701156a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0423\u0441\u043b\u043e\u0432\u043d\u044b\u0435 \u0422\u0438\u043f\u044b", "Name_src": "Conditional Types", "Text": "\u0423\u0441\u043b\u043e\u0432\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0433\u043e \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \u0423\u0441\u043b\u043e\u0432\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u044b \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0431\u0449\u0435\u043c\u0443 \u0442\u0438\u043f\u0443 \u0438 \u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u043c \u0441 \u043d\u0438\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u043d\u044b\u043c \u0442\u0438\u043f\u0430\u043c. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u043e\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u0438\u043b\u0438 \u0440\u0430\u0437\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u043a\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \n
    \n
    \n\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0443\u0441\u043b\u043e\u0432\u043d\u043e\u043c\u0443 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c\u0443 \u043e\u043a\u043d\u0443 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043d\u043e\u043f\u043a\u0438 \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u0430\u00bb \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0422\u0438\u043f\u043e\u0432 \u0414\u0430\u043d\u043d\u044b\u0445\", \u0435\u0441\u043b\u0438 \u0432\u043a\u043b\u044e\u0447\u0435\u043d \u043f\u043e\u043a\u0430\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a. \u041a\u0430\u0436\u0434\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u043f\u043e\u043b\u0435, \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f. \u0412 \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u043e\u0432 \u0432\u0445\u043e\u0434\u044f\u0442 \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u043e, \u0431\u043e\u043b\u044c\u0448\u0435, \u043c\u0435\u043d\u044c\u0448\u0435, [\u0431\u043e\u043b\u044c\u0448\u0435 \u0438\u043b\u0438 \u0440\u0430\u0432\u043d\u043e, \u043c\u0435\u043d\u044c\u0448\u0435 \u0438\u043b\u0438 \u0440\u0430\u0432\u043d\u043e], \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441, \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442. \u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0442 \u0442\u0430\u043a\u0436\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u0418\u0441\u0442\u0438\u043d\u0430 \u0438 \u041b\u043e\u0436\u044c, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u044e\u0442 \u0442\u0438\u043f \u0432\u0441\u0435\u0445 \u0443\u0437\u043b\u043e\u0432 \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e.\n
    \n
    \u0414\u043b\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u0442\u0438\u043f\u043e\u0432 \u043f\u043e\u043b\u0435\u0439, \u0442\u0430\u043a\u0438\u0445 \u043a\u0430\u043a \u0434\u0430\u0442\u044b, \u0432\u0440\u0435\u043c\u044f \u0438 \u043b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u0432 \u0442\u043e\u043c \u0436\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0435, \u0447\u0442\u043e \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u043a\u043d\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430 \u0434\u0430\u043d\u043d\u044b\u0445. \u0412 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u044b \u00ab\u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441\u00bb, \u00ab\u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430\u00bb \u0438 \u00ab\u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442\u00bb \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u044d\u0442\u0438\u0445 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u043b\u0435\u0439, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u0414\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043c\u044f \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u0441\u0440\u0430\u0432\u043d\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u00ab\u0421\u0435\u0439\u0447\u0430\u0441\u00bb, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u0430\u043a \u0442\u0435\u043a\u0443\u0449\u0430\u044f \u0434\u0430\u0442\u0430 \u0438 \u0432\u0440\u0435\u043c\u044f. \u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0438\u00bb \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044e\u0449\u0438\u0445\u0441\u044f \u043d\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441\u0441\u044b\u043b\u043e\u043a.\n
    \n
    \n\u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u043e\u0432\u043e\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u043e\u00bb \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0442\u0440\u043e\u043a \u0443\u0441\u043b\u043e\u0432\u0438\u0439. \u0421\u0442\u0440\u043e\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u00ab\u0438\u00bb \u0438\u043b\u0438 \u00ab\u0438\u043b\u0438\u00bb. \u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u043e\u00bb \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u044e\u044e \u0441\u0442\u0440\u043e\u043a\u0443 \u0443\u0441\u043b\u043e\u0432\u0438\u044f. \u0415\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0434\u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0430, \u043a\u043d\u043e\u043f\u043a\u0430 \u00ab\u0423\u0434\u0430\u043b\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u043e\u00bb \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0443\u0434\u0430\u043b\u0438\u0442 \u0443\u0441\u043b\u043e\u0432\u0438\u0435.\n
    \n
    \n\u041d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0443\u0441\u043b\u043e\u0432\u0438\u044f \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0442\u0438\u043f\u043e\u0432 \u0432 \u0441\u0435\u043c\u0435\u0439\u0441\u0442\u0432\u0435. \u0415\u0441\u043b\u0438 \u0434\u043b\u044f \u0443\u0437\u043b\u0430 \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043d\u0438\u043a\u0430\u043a\u0438\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u044f, \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0430 \u0432\u044b\u0431\u0435\u0440\u0435\u0442 \u043f\u0443\u0441\u0442\u043e\u0435 \u0443\u0441\u043b\u043e\u0432\u0438\u0435, \u0430 \u043d\u0435 \u043b\u043e\u0436\u043d\u043e\u0435.\n
    \n
    \n\u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0441\u043c. \u0444\u0430\u0439\u043b \"sample_conditional_todo\" (\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \"\u0424\u0430\u0439\u043b > \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u041f\u0440\u0438\u043c\u0435\u0440\").", "Text_src": "Conditional expressions can be used to automatically assign a data type based on each node's content. Conditions can be assigned only to a generic type and its associated derived types. This allows the automatic assignment of different output formatting or different icons depending on each node's field data.\n

    \nThe conditional dialog box is accessed from a button on the \"Type Config\" tab of the \"Data->Configure Types Dialog\" if the advanced functions are shown. Each line of the condition includes a field, an operator and a comparison value. The operators include equality, greater than, less than, starts with, ends with, and contains. There are also True and False operators that will toggle the type of all nodes simultaneously.\n

    \nFor special field types such as dates, times, and booleans, the comparison value should be entered in the same format that is used in the Data Editor window. In general, the starts with, ends with, and contains operators should not be used for these special fields, since the comparison is done using an internal data representation. Dates and times also support a special comparison value of \"Now\", which is always interpreted as the current date and time. The \"Data->Regenerate References\" command may be needed to force re-evaluation of time-based references.\n

    \nThe \"Add New Rule\" button is used to add additional condition lines. The lines can be joined with \"and\" or \"or\" operators. The \"Remove Rule\" button deletes the last condition line. If only a single line is present, the \"Remove Rule\" button completely removes the condition.\n

    \nConditions do not have to be set for all types in a family. If no conditions are true for a node, the program will select a blank condition rather than a false one.\n

    \nFor an example, see the \"sample_conditional_todo\" file (by using the \"File > Open Sample\" command)." }, "format": "HEAD_PARA", "uid": "f170125aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c\u044b\u0435 \u0424\u043e\u0440\u043c\u0430\u0442\u044b", "Name_src": "Copying Formats", "Text": "\u0414\u0440\u0443\u0433\u043e\u0439 \u043c\u0435\u0442\u043e\u0434 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0442\u0438\u043f\u0430 \u0434\u0430\u043d\u043d\u044b\u0445 \u2014 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432 \u0438\u0437 \u0434\u0440\u0443\u0433\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 TreeLine. \u042d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0422\u0438\u043f\u044b \u0438\u0437 \u0424\u0430\u0439\u043b\u0430\u00bb. \u041f\u0440\u0438 \u0435\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432\u0441\u0435 \u0442\u0438\u043f\u044b \u0438\u0437 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430. \u041b\u044e\u0431\u044b\u0435 \u0442\u0438\u043f\u044b \u0432 \u0442\u0435\u043a\u0443\u0449\u0435\u043c \u0444\u0430\u0439\u043b\u0435 \u0441 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u043c\u0438 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u044e\u0442\u0441\u044f, \u043d\u043e \u0442\u0438\u043f\u044b \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e\u0442\u0441\u044f.", "Text_src": "Another method for changing data type formatting is to copy the formats from another TreeLine file. This is done with the \"Data > Copy Types from File\" command. All types from the chosen file are copied. Any types in the current file with matching names are overwritten, but types with unique names are retained." }, "format": "HEAD_PARA", "uid": "f1701368a25a11e7b7c67054d2175f18" }, { "children": [ "f170155ca25a11e7b7c67054d2175f18", "f1701660a25a11e7b7c67054d2175f18", "f1701764a25a11e7b7c67054d2175f18", "f1701868a25a11e7b7c67054d2175f18", "f170198aa25a11e7b7c67054d2175f18", "f1701a8ea25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 \u0414\u0430\u043d\u043d\u044b\u043c\u0438 \u0414\u0435\u0440\u0435\u0432\u0430", "Name_src": "Tree Data Operations" }, "format": "HEADINGS", "uid": "f170146ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430", "Name_src": "Sorting", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u0421\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0437\u043b\u044b\u00bb \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0443\u0437\u043b\u044b \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0443\u0437\u043b\u043e\u0432 \u0438\u043b\u0438 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u043f\u043e\u043b\u0435\u0439, \u0440\u0430\u043d\u0435\u0435 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u043d\u044b\u0445 \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0435 \u0442\u0438\u043f\u0430 \u0443\u0437\u043b\u0430. \u041f\u0440\u0435\u0434\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043f\u043e\u043b\u044f\u00bb [\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043d\u0435\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c, \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u043a\u0430\u043a \u0432 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u0439 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u043b\u044f \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u2014 \u0435\u0441\u043b\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0443 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0430 \u043f\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430\u043c, \u0442\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u0434\u0435\u0440\u0435\u0432\u0430 \u043d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0412\u044b\u0432\u043e\u0434\u00bb] \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u00ab\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 \u0434\u0430\u043d\u043d\u044b\u0445\u00bb. \u041a\u043d\u043e\u043f\u043a\u0430 \u00ab\u041a\u043b\u044e\u0447\u0438 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438\u00bb [\u043d\u0430 \u0432\u043a\u043b\u0430\u0434\u043a\u0435 \u00ab\u0421\u043f\u0438\u0441\u043e\u043a \u041f\u043e\u043b\u0435\u0439\u00bb] \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043f\u043e\u043b\u0435\u0439, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u044e\u0449\u0438\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043b\u044e\u0447\u0435\u0439 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438. \u041f\u043e\u043b\u044f \u0432\u044b\u0448\u0435 \u0432 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0438\u043c\u0435\u044e\u0442 \u0431\u043e\u043b\u0435\u0435 \u0432\u044b\u0441\u043e\u043a\u0438\u0439 \u043f\u0440\u0438\u043e\u0440\u0438\u0442\u0435\u0442. \u041d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u043e\u0433\u043e \u043f\u043e\u043b\u044f [\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432] \u043c\u043e\u0436\u043d\u043e \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0435.", "Text_src": "The \"Data > Sort Nodes\" command can sort nodes based on either node titles or key fields predefined in the node type configuration. The predefined sort fields can be changed in the \"Field Config\" tab of the Configure Types Dialog. The \"Sort Keys\" button brings up a list of fields that define a sort key sequence. The fields higher in the sequence have a higher priority. The direction for each key field can be flipped." }, "format": "HEAD_PARA", "uid": "f170155ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044f", "Name_src": "Numbering", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 > \u041e\u0431\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u044e\u00bb \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u043f\u043e\u043b\u0435\u0439 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u043f\u043e\u043b\u044f \u2014 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438. \u0424\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0432\u043e\u0434\u0430 \u043f\u043e\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0447\u0438\u0441\u0435\u043b \u0432 \u0432\u044b\u0432\u043e\u0434\u0435, \u0432\u043a\u043b\u044e\u0447\u0430\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0447\u0438\u0441\u0435\u043b, \u043d\u043e\u043c\u0435\u0440\u043e\u0432 \u0432 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0438\u043b\u0438 \u0441\u0445\u0435\u043c\u044b \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432. \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u0441\u043c. \u0432 \u0422\u0438\u043f \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438.\n
    \n
    \n\u041e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435, \u0447\u0442\u043e \u043f\u043e\u043b\u044f \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u043d\u0435 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043e\u043a\u043d\u0435 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445, \u0435\u0441\u043b\u0438 \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u0444\u043b\u0430\u0436\u043e\u043a \u00ab\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044f \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0432 \u0420\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0414\u0430\u043d\u043d\u044b\u0445\u00bb \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b > \u0414\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0424\u0443\u043d\u043a\u0446\u0438\u0438\u00bb. \u041a\u043e\u0433\u0434\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0435 \u0434\u0430\u043d\u043d\u044b\u0445, \u043e\u043d\u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432 \u0441\u0442\u0438\u043b\u0435 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432, \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 \u0432\u044b\u0432\u043e\u0434\u0430.", "Text_src": "The \"Data > Update Numbering\" command updates the contents of fields with a special numbering field type. The field's output format defines how the numbers are displayed in the output, including whether individual numbers, outline numbers or a section numbering scheme are shown. See the Numbering Field Type for more information.
    \n
    \nNote that numbering fields are not shown in the data edit view unless \"Show numbering fields in the Data Edit View\" is checked under \"Tools > General Options > Features Available\". When they are shown in the data edit view, they show up in section numbering style, regardless of the output format." }, "format": "HEAD_PARA", "uid": "f1701660a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u043e\u0438\u0441\u043a \u0438 \u0417\u0430\u043c\u0435\u043d\u0430", "Name_src": "Find and Replace", "Text": "\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041f\u043e\u0438\u0441\u043a \u0438 \u0417\u0430\u043c\u0435\u043d\u0430\u00bb \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 [\u0441\u0440\u0430\u0437\u0443] \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0443\u0437\u043b\u0430\u0445. \u0412 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0442\u0435\u043a\u0441\u0442 \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0438 \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0439 \u0442\u0435\u043a\u0441\u0442. \u041f\u043e\u0438\u0441\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0441\u043d\u043e\u0432\u0430\u043d \u043d\u0430 \u043b\u044e\u0431\u043e\u043c \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0438 \u0432\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u0439, \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u043d\u044b\u0445 \u0441\u043b\u043e\u0432\u0430\u0445 \u0438\u043b\u0438 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u043c \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0438 Python [\u0441\u043c. \u041f\u043e\u0438\u0441\u043a]. \u041f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u0442\u0438\u043f\u043e\u043c \u0443\u0437\u043b\u0430 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u043c \u043f\u043e\u043b\u0435\u043c \u0443\u0437\u043b\u0430. \n
    \n
    \n\u0417\u0430\u043c\u0435\u043d\u0430 \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u2014 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043e\u0449\u043d\u044b\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442. \u041f\u0440\u0438 \u043f\u043e\u0438\u0441\u043a\u0435 \". *\" \u0411\u0443\u0434\u0435\u0442 \u043d\u0430\u0439\u0434\u0435\u043d \u0432\u0435\u0441\u044c \u0442\u0435\u043a\u0441\u0442 \u0432 \u043f\u043e\u043b\u0435. \u0421\u0442\u0440\u043e\u043a\u0430 \u0437\u0430\u043c\u0435\u043d\u044b \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0442\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u0435 \u0438\u0437 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u0439 \u043a\u043e\u0441\u043e\u0439 \u0447\u0435\u0440\u0442\u044b \u0438 \u0447\u0438\u0441\u043b\u0430. \u041e\u0431\u0440\u0430\u0442\u043d\u044b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0437\u0430\u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u0433\u0440\u0443\u043f\u043f\u043e\u0439 \u0432 \u0441\u043a\u043e\u0431\u043a\u0430\u0445 \u0438\u0437 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u00ab\\2\u00bb \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043c\u0435\u043d\u0435\u043d \u0442\u0435\u043a\u0441\u0442\u043e\u043c, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0442\u043e\u0440\u043e\u0439 \u0433\u0440\u0443\u043f\u043f\u0435 \u0438\u0437 \u0441\u043a\u043e\u0431\u043e\u043a. \"\\g<0>\" \u043e\u0431\u0440\u0430\u0442\u043d\u0430\u044f \u0441\u0441\u044b\u043b\u043a\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044b \u0432\u0441\u0435\u0439 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u0439 \u0441\u0442\u0440\u043e\u043a\u0438.", "Text_src": "The \"Tools > Find and Replace\" command can be used to change the text in several nodes. The search text and replacement text are entered. Searching can be based on any match, full words only, or a Python regular expression. The operation can optionally be restricted to a particular node type and to a particular node field.
    \n
    \nReplacement using regular expressions is quite powerful. Searching for \".*\" will match all of the text in the field. The replacement string can contain back references that consist of a backslash and a number. The back references get replaced with the corresponding parenthesized group from the match. For example, \"\\2\" will be replaced with the text that matched the second group of parenthesis. The \"\\g<0>\" back-reference can be used to substitute the entire matching string." }, "format": "HEAD_PARA", "uid": "f1701764a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u041f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u044f", "Name_src": "Spell Check", "Text": "\u0412 \u043c\u0435\u043d\u044e \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b\u00bb \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u043e\u0440\u0444\u043e\u0433\u0440\u0430\u0444\u0438\u0438. \u0414\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b (aspell, ispell \u0438\u043b\u0438 hunspell \u2014 \u0441\u043c. \u0420\u0430\u0437\u0434\u0435\u043b \u0421\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u044f ). \u0415\u0441\u043b\u0438 \u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u0432\u0435\u0442\u043a\u0435 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 \u0441\u043b\u043e\u0432\u0430 \u0441 \u043e\u0448\u0438\u0431\u043a\u0430\u043c\u0438, \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u0438 \u0441\u043b\u043e\u0432\u0430, \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0441\u043b\u043e\u0432\u0430\u0440\u044c, \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438\u043b\u0438 \u043e\u0442\u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043f\u0440\u0430\u0432\u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u0442\u0435\u043a\u0441\u0442\u0430 \u0432\u043e \u0432\u0441\u0435\u0445 \u043f\u043e\u043b\u044f\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430.", "Text_src": "There is a spell check command in the \"Tools\" menu. Use of this command requires an external program to be installed (either aspell, ispell or hunspell- see the System Requirements section). If there are any misspelled words in the selected branch, a dialog will allow the word to be ignored, added to the dictionary, replaced with a suggestion or edited. This will spell check the text in all data fields of each node." }, "format": "HEAD_PARA", "uid": "f1701868a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0423\u0437\u043b\u044b", "Name_src": "Cloned Nodes", "Text": "\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u0434\u0435\u0440\u0435\u0432\u0430. \u0420\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438\u043b\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u0432 \u043e\u0434\u043d\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u0438\u0437\u043c\u0435\u043d\u044f\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0432\u043e \u0432\u0441\u0435\u0445 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0435\u0441\u0442\u0430\u0445. \u041a\u043e\u0433\u0434\u0430 \u0432\u044b\u0431\u0440\u0430\u043d \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0443\u0437\u0435\u043b, \u0432 \u043f\u0430\u043d\u0435\u043b\u0438 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u043e\u043d\u043d\u043e\u0439 \u0446\u0435\u043f\u043e\u0447\u043a\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a, \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0445 \u0443\u0437\u043b\u044b-\u043f\u0440\u0435\u0434\u043a\u0438, \u0443 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u0439. \u0412\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0443\u0437\u0435\u043b \u0431\u0443\u0434\u0435\u0442 \u0447\u0435\u0440\u043d\u044b\u043c (\u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441\u0441\u044b\u043b\u043a\u043e\u0439), \u043d\u043e \u043f\u043e \u0435\u0433\u043e \u0435\u0433\u043e \u043a\u043b\u043e\u043d\u0430\u043c \u043c\u043e\u0436\u043d\u043e \u0449\u0435\u043b\u043a\u043d\u0443\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0438\u0445 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435.\n
    \n
    \n\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u043f\u0443\u0442\u0435\u043c \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0443\u0437\u043b\u043e\u0432 \u0438\u043b\u0438 \u0432\u0435\u0442\u0432\u0435\u0439, \u0430 \u0437\u0430\u0442\u0435\u043c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0445 \u043a\u043e\u043c\u0430\u043d\u0434 \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438\u0437 \u043c\u0435\u043d\u044e \u00ab\u041f\u0440\u0430\u0432\u043a\u0430\u00bb \u0434\u043b\u044f \u0438\u0445 \u0432\u0441\u0442\u0430\u0432\u043a\u0438 \u0432 \u0434\u0440\u0443\u0433\u043e\u0435 \u043c\u0435\u0441\u0442\u043e [\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u0447\u0442\u043e \u0432 \u044d\u0442\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0432\u0441\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0443\u0437\u0435\u043b \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442, \u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0432\u043f\u0430\u0432\u0448\u0438\u0435 \u0443\u0437\u043b\u044b\u00bb, \u0441\u043c. \u043d\u0438\u0436\u0435]. \u0421\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043a\u043b\u043e\u043d \u043c\u043e\u0436\u043d\u043e \u0443\u0434\u0430\u043b\u0438\u0442\u044c, \u0443\u0434\u0430\u043b\u0438\u0432 \u0443\u0437\u043b\u044b \u0438\u043b\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 & gt; \u041e\u0442\u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u043a\u043b\u043e\u043d\u044b\u00bb, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0438\u0445 \u043e\u0431\u0440\u0430\u0442\u043d\u043e \u0432 \u043e\u0431\u044b\u0447\u043d\u044b\u0435 \u0443\u0437\u043b\u044b.
    \n
    \n\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0414\u0430\u043d\u043d\u044b\u0435 & gt; \u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0432\u043f\u0430\u0432\u0448\u0438\u0435 \u0443\u0437\u043b\u044b\u00bb. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442 \u0432\u0441\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b\u0435 \u0443\u0437\u043b\u044b \u0432 \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0432 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b. [\u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u044d\u0442\u043e \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0443\u0437\u043b\u044b \u2014 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0432\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0439 \u0443\u0437\u0435\u043b, \u0430 \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u00ab\u041a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u0441\u043e\u0432\u043f\u0430\u0432\u0448\u0438\u0435 \u0443\u0437\u043b\u044b\u00bb].\n
    \n
    \n\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f\u043c\u0438 \u0441\u043c. \u0432 \u0444\u0430\u0439\u043b\u0435 \u00absample_genealogy\u00bb (\u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0424\u0430\u0439\u043b> \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u041f\u0440\u0438\u043c\u0435\u0440\u00bb).", "Text_src": "Cloned nodes are used to duplicate sections of the tree. Editing their data or child structure in one location changes all locations. When a cloned node is selected, multiple lines are shown in the Breadcrumb view, showing ancestor nodes that have multiple parents. The selected node will appear black (not a link), but its clones can be clicked to select their location in the tree view.
    \n
    \nCloned nodes are created by copying nodes or branches and then using the special paste clone commands found in the \"Edit\" menu to paste them elsewhere. The clone link can be removed by deleting the nodes or by using the \"Data > Detach Clones\" command to convert them back to regular nodes.
    \n
    \nCloned nodes can also be created automatically by using the \"Data > Clone All Matched Nodes\" command. This will convert all identical nodes in the tree structure into cloned nodes.
    \n
    \nFor an example of cloned nodes with multiple parents, see the \"sample_genealogy\" file (by using the \"File > Open Sample\" command)." }, "format": "HEAD_PARA", "uid": "f170198aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0420\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u041a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438", "Name_src": "Category-Based Arrangement", "Text": "\u041c\u0435\u043d\u044e \u00ab\u0414\u0430\u043d\u043d\u044b\u0435\u00bb \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0434\u043b\u044f \u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0438 \u0432\u044b\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f\u043c. \u042d\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u044f \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0443\u0437\u043b\u043e\u0432 \u043d\u0438\u0436\u0435 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0443\u0437\u043b\u0430 \u0432 \u0434\u0435\u0440\u0435\u0432\u0435. \n
    \n
    \n\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438\u00bb \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u0430\u043c \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u0434\u043d\u043e \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u043b\u0435\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0431\u0449\u0438\u043c\u0438 \u0434\u043b\u044f \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432. \u042d\u0442\u0438 \u043f\u043e\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0443\u0437\u043b\u043e\u0432 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439, \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u044f \u0438\u0445 \u043f\u043e \u043e\u0431\u0449\u0438\u043c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f\u043c. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u0441\u043f\u0438\u0441\u043a\u0435 \u043a\u043d\u0438\u0433 \u0432\u044b\u0431\u043e\u0440 \u043f\u043e\u043b\u0435\u0439 \u00abauthor_first_name\u00bb \u0438 \u00abauthor_last_name\u00bb \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u0442 \u043a \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e \u0434\u0435\u0440\u0435\u0432\u0430 \u0441 \u043a\u043d\u0438\u0433\u0430\u043c\u0438 \u0432 \u043d\u043e\u0432\u044b\u0445 \u0443\u0437\u043b\u0430\u0445 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0430\u0432\u0442\u043e\u0440\u0430. \n
    \n
    \n\u041a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0421\u0432\u0435\u0441\u0442\u0438 \u0432 \u043e\u0434\u0438\u043d \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u043e \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438\u00bb \u043f\u043e\u0447\u0442\u0438 \u043f\u0440\u043e\u0442\u0438\u0432\u043e\u043f\u043e\u043b\u043e\u0436\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u00ab\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0438\u00bb. \u0414\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u043b\u044e\u0431\u044b\u0435 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0443\u0437\u043b\u044b \u0441 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438, \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u044f \u043f\u043e\u043b\u044f \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0438\u0437 \u043d\u0438\u0445 [\u0432\u043d\u0443\u0447\u0430\u0442\u044b\u0445 \u0443\u0437\u043b\u043e\u0432] \u0441\u0432\u043e\u0438\u043c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c \u0443\u0437\u043b\u0430\u043c. \u041e\u043d\u0430 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0438\u043c\u0435\u043d\u043e\u0432\u044b\u0432\u0430\u0442\u044c \u043f\u043e\u043b\u044f \u0432\u043c\u0435\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0441\u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u043f\u043e\u043b\u0435\u0439, \u043d\u043e \u044d\u0442\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u0430, \u043a\u043e\u0433\u0434\u0430 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0435 \u0443\u0437\u043b\u044b \u043e\u0442\u043d\u043e\u0441\u044f\u0442\u0441\u044f \u043a \u0440\u0430\u0437\u043d\u044b\u043c \u0442\u0438\u043f\u0430\u043c \u0441 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u0438\u043c\u0435\u043d\u0430\u043c\u0438 \u043f\u043e\u043b\u0435\u0439.\n
    \n
    \n\u0422\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u041f\u043e\u043c\u0435\u043d\u044f\u0442\u044c \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0443\u0440\u043e\u0432\u043d\u0438 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u0439\u00bb, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043c\u0435\u043d\u044f\u0435\u0442 \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u0438 \u0432\u043d\u0443\u0447\u0430\u0442\u044b\u0439 \u0443\u0437\u043b\u044b \u043f\u043e\u0434 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u0443\u0437\u043b\u043e\u043c. \u0414\u043e\u0447\u0435\u0440\u043d\u0438\u0439 \u0443\u0437\u0435\u043b \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438 \u043f\u043e\u0434 \u043d\u0438\u043c \u0431\u0443\u0434\u0435\u0442 \u043a\u043b\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u0438\u0437 \u043d\u0438\u0445. \u041b\u044e\u0431\u044b\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043a\u043b\u043e\u043d\u044b \u0432\u043d\u0443\u043a\u043e\u0432 \u0441\u0442\u0430\u043d\u0443\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438 \u0441 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u043c\u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430\u043c\u0438.", "Text_src": "The \"Data\" menu contains commands for arranging and flattening the data by category. These methods are used to automatically add and remove levels of nodes below the current node in the tree.\n
    \n
    \nThe \"Add Category Level\" command allows you to select one or more of the fields that the child nodes have in common. These fields are used to create new parent nodes for the children, grouping them by common categories. For example, in a list of books, picking the \"author_first_name\" and \"author_last_name\" fields will result in a tree with the books under new nodes for each unique author.\n
    \n
    \nThe \"Flatten by Category\" command is almost the opposite of \"Add Category Level\". It eliminates any descendant nodes with children, transferring their data fields to their children. It will rename fields instead of overwriting data with the same field names, but this command is most useful when the children and parents are different types with unique field names.\n
    \n
    \nThere is also a \"Swap Category Levels\" command that will swap the child and grandchild nodes beneath a selected node. A child node with multiple nodes under it will become cloned under each one. Any existing grandchild clones will become individual nodes with multiple children." }, "format": "HEAD_PARA", "uid": "f1701a8ea25a11e7b7c67054d2175f18" }, { "children": [ "fd0fe3dd69dc11ebab13001fd026534b", "0a0d866469dd11eb9819001fd026534b", "12aaf67e69dd11eb9d47001fd026534b" ], "data": { "Name": "\u041f\u0435\u0447\u0430\u0442\u044c", "Name_src": "Printing" }, "format": "HEADINGS", "uid": "f1701caaa25a11e7b7c67054d2175f18" }, { "children": [ "f170216ea25a11e7b7c67054d2175f18", "f1702272a25a11e7b7c67054d2175f18", "f170236ca25a11e7b7c67054d2175f18", "f1702470a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0444\u0430\u0439\u043b\u043e\u0432", "Name_src": "File Handling" }, "format": "HEADINGS", "uid": "f170207ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u0436\u0430\u0442\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432", "Name_src": "File Compression", "Text": "\u0424\u0430\u0439\u043b TreeLine \u0438\u043c\u0435\u0435\u0442 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 JSON. \u0412 \u043d\u0435\u043c \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0436\u0430\u0442\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432 (\u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 gzip) \u0434\u043b\u044f \u044d\u043a\u043e\u043d\u043e\u043c\u0438\u0438 \u043c\u0435\u0441\u0442\u0430 \u043d\u0430 \u0434\u0438\u0441\u043a\u0435. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0441\u0436\u0430\u0442\u044b \u043b\u0438\u0431\u043e \u0438\u0437 \u043c\u0435\u043d\u044e \u00ab\u0424\u0430\u0439\u043b > \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u00bb, \u043b\u0438\u0431\u043e \u0438\u0437 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u0433\u043e\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0430 \u0442\u0438\u043f\u043e\u0432 \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u00ab\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u00bb [\u043f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u0442\u0438\u043f\u0430 \u0444\u0430\u0439\u043b\u0430].", "Text_src": "A TreeLine file is in a JSON text format. There are options to compress the files (gzip format) to save storage space. Individual files can be set to compressed mode from either \"File > Properties\" or from the file type pull-down in the save-as dialog." }, "format": "HEAD_PARA", "uid": "f170216ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0428\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432", "Name_src": "File Encryption", "Text": "\u0412 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u043e\u043f\u0446\u0438\u044f \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u043e\u0432 TreeLine \u0434\u043b\u044f \u0438\u0445 \u0437\u0430\u0449\u0438\u0442\u044b \u043e\u0442 \u043d\u0435\u0441\u0430\u043d\u043a\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043f\u0430\u0440\u043e\u043b\u0435\u043c. \u041e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0448\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u044b \u043b\u0438\u0431\u043e \u0447\u0435\u0440\u0435\u0437 \u043c\u0435\u043d\u044e \u00ab\u0424\u0430\u0439\u043b> \u0421\u0432\u043e\u0439\u0441\u0442\u0432\u0430\u00bb, \u043b\u0438\u0431\u043e \u0432 \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u043c\u0441\u044f \u0441\u043f\u0438\u0441\u043a\u0435 \u0442\u0438\u043f\u043e\u0432 \u0444\u0430\u0439\u043b\u043e\u0432 \u0432 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u043c \u043e\u043a\u043d\u0435 \u00ab\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043a\u0430\u043a\u00bb. \u0428\u0438\u0444\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 \u0445\u044d\u0448-\u0444\u0443\u043d\u043a\u0446\u0438\u044e SHA \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u0448\u0438\u0444\u0440\u0430 \u2014 \u044d\u0442\u043e\u0442 \u0441\u043f\u043e\u0441\u043e\u0431 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0432\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u044b\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438.", "Text_src": "There is a file encryption option to password protect TreeLine files. Individual files can be set to encrypted mode from either \"File > Properties\" or from the file type pull-down in the save-as dialog. The encryption uses an SHA hash function as a stream cipher - it should be fairly secure." }, "format": "HEAD_PARA", "uid": "f1702272a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0410\u0432\u0442\u043e\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435", "Name_src": "Auto-Save", "Text": "\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0430\u0432\u0442\u043e\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0442\u044c \u043d\u0435\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b \u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u043c \u0441\u0438\u043c\u0432\u043e\u043b\u0430 \u00ab~\u00bb \u043a \u0438\u043c\u0435\u043d\u0438 \u0444\u0430\u0439\u043b\u0430. \u0424\u0430\u0439\u043b\u044b \u0440\u0435\u0437\u0435\u0440\u0432\u043d\u044b\u0445 \u043a\u043e\u043f\u0438\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u0434\u0430\u043b\u044f\u044e\u0442\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u0444\u0430\u0439\u043b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0438\u043b\u0438 \u0440\u0430\u0431\u043e\u0442\u0430 TreeLine \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f \u0431\u0435\u0437 \u043e\u0448\u0438\u0431\u043e\u043a. \u0412\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0430\u0432\u0442\u043e\u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u00ab\u041e\u0431\u0449\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445\u00bb. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043d\u0443\u043b\u0435\u0432\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u044d\u0442\u0443 \u0444\u0443\u043d\u043a\u0446\u0438\u044e.", "Text_src": "An auto-save feature can store unsaved files with a \"~\" appended to the file name. The backup files are automatically removed when the file is saved or TreeLine exits cleanly. The auto-save time interval is set in the general options. Setting the interval to zero disables this feature." }, "format": "HEAD_PARA", "uid": "f170236ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u044b\u0435 \u0421\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u0414\u0435\u0440\u0435\u0432\u0430", "Name_src": "Saved Tree States", "Text": "\u041f\u0440\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u0438 \u043d\u0435\u0434\u0430\u0432\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0444\u0430\u0439\u043b\u0430 TreeLine \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0445 \u0438 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0445 \u0443\u0437\u043b\u043e\u0432. \u042d\u0442\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 TreeLine \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u041f\u0440\u0438 \u0436\u0435\u043b\u0430\u043d\u0438\u0438 \u044d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0432 \u043e\u043a\u043d\u0435 \u00ab\u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b\u00bb.", "Text_src": "When opening a recently used file, TreeLine will restore the states of open and selected nodes. This information is stored in the user's TreeLine configuration files. If desired, this feature can be disabled with a general option." }, "format": "HEAD_PARA", "uid": "f1702470a25a11e7b7c67054d2175f18" }, { "children": [ "f170265aa25a11e7b7c67054d2175f18", "f170275ea25a11e7b7c67054d2175f18", "f1702b46a25a11e7b7c67054d2175f18", "95547c38b97411e7a42a3417ebd53aeb", "f1702858a25a11e7b7c67054d2175f18", "f1702952a25a11e7b7c67054d2175f18", "f1702a42a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 \u0424\u0430\u0439\u043b\u043e\u0432", "Name_src": "File Import" }, "format": "HEADINGS", "uid": "f170256aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u0431\u0449\u0438\u0435 \u0421\u0432\u0435\u0434\u0435\u043d\u0438\u044f", "Name_src": "General Information", "Text": "\u0424\u0430\u0439\u043b\u044b TreeLine \u0438\u043c\u0435\u044e\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 JSON. \u0424\u0430\u0439\u043b\u044b \u0434\u0440\u0443\u0433\u0438\u0445 \u0442\u0438\u043f\u043e\u0432 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0424\u0430\u0439\u043b > \u0418\u043c\u043f\u043e\u0440\u0442\u00bb, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0435\u0435 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0442\u0438\u043f \u0438\u043c\u043f\u043e\u0440\u0442\u0430. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u044b \u0434\u043b\u044f \u0432\u044b\u0437\u043e\u0432\u0430 \u044d\u0442\u043e\u0433\u043e \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0433\u043e \u043e\u043a\u043d\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u00ab\u0424\u0430\u0439\u043b > \u041e\u0442\u043a\u0440\u044b\u0442\u044c\u00bb \u043d\u0430 \u0444\u0430\u0439\u043b \u0441 \u043e\u0442\u043b\u0438\u0447\u043d\u044b\u043c \u043e\u0442 TreeLine \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c.", "Text_src": "A TreeLine file is in a specific JSON text format. Other types of files can be imported using the \"File > Import\" command, which will show a dialog box where the type of import can be selected. Alternatively, using the \"File > Open\" command with a non-TreeLine file will also show this dialog." }, "format": "HEAD_PARA", "uid": "f170265aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 \u0422\u0435\u043a\u0441\u0442\u0430", "Name_src": "Text Import", "Text": "\u0414\u043b\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0432\u044b\u0431\u0440\u0430\u043d\u044b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0445 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u0432. \u0422\u0435\u043a\u0441\u0442 \u0441 \u043e\u0442\u0441\u0442\u0443\u043f\u0430\u043c\u0438 \u0432 \u0432\u0438\u0434\u0435 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0443\u0437\u043b\u0430 \u0438\u0437 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0444\u0430\u0439\u043b\u0435 \u0441\u043e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439, \u043e\u0441\u043d\u043e\u0432\u044b\u0432\u0430\u044e\u0449\u0435\u0439\u0441\u044f \u043d\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u0439 \u043f\u0435\u0440\u0435\u0434 \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u043e\u0439.\n
    \n
    \n\u0412 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u0437\u0430\u043f\u044f\u0442\u044b\u043c\u0438 (CSV) \u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0445 \u0442\u0430\u0431\u043b\u0438\u0446\u0430\u0445, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0445 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u044f\u043c\u0438, \u043f\u0435\u0440\u0432\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043c\u0435\u043d \u043f\u043e\u043b\u0435\u0439, \u0437\u0430\u0442\u0435\u043c \u043a\u0430\u0436\u0434\u0430\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0441\u0442\u0440\u043e\u043a\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0443\u0437\u043b\u043e\u043c \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u043b\u044f, \u0432\u0437\u044f\u0442\u044b\u043c\u0438 \u0438\u0437 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0442\u043e\u043b\u0431\u0446\u0430. \u0418\u043c\u043f\u043e\u0440\u0442 CSV \u0441 \u043d\u043e\u043c\u0435\u0440\u0430\u043c\u0438 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0434\u0435\u0440\u0435\u0432\u043e \u0438\u0437 \u043d\u043e\u043c\u0435\u0440\u043e\u0432 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0432 \u043f\u0435\u0440\u0432\u043e\u043c \u0441\u0442\u043e\u043b\u0431\u0446\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u044e\u0442\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u043e\u0442\u043d\u043e\u0448\u0435\u043d\u0438\u044f. \n
    \n
    \n\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430, \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u0443\u0437\u043b\u0443 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443, \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043f\u043b\u043e\u0441\u043a\u043e\u0435 [\u043e\u0434\u043d\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e\u0435] \u0434\u0435\u0440\u0435\u0432\u043e, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0435\u0435 \u0438\u0437 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432 \u0443\u0437\u043b\u043e\u0432.\n
    \n
    \n\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043f\u0440\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0435 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u0441 \u0430\u0431\u0437\u0430\u0446\u0430\u043c\u0438 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u0443\u0437\u043b\u044b \u0441 \u043f\u043e\u043b\u044f\u043c\u0438, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u043c\u0438 \u0434\u043b\u0438\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0438\u0437 \u0442\u0435\u043a\u0441\u0442\u0430, \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0443\u0441\u0442\u044b\u043c\u0438 \u0441\u0442\u0440\u043e\u043a\u0430\u043c\u0438.", "Text_src": "Several different text formats can be selected for import. Tab indented text creates a node title from each line in the file, structured based on the number of tabs before each line.
    \n
    \nThe comma-delimited (CSV) and the tab delimited text tables use the first line as a header row to create field names, then each additional row becomes a node with field data taken from each column. The CSV import with level numbers creates a tree structure from level numbers in the first column that are incremented to show child relationships.
    \n
    \nThe plain text, one node per line import creates a flat tree of node titles.
    \n
    \nFinally, the plain text paragraph import creates long text nodes from text separated by blank lines." }, "format": "HEAD_PARA", "uid": "f170275ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 \u0444\u0430\u0439\u043b\u043e\u0432 Treepad", "Name_src": "Treepad Import", "Text": "\u0424\u0430\u0439\u043b\u044b \u0438\u0437 \u0443\u0441\u043b\u043e\u0432\u043d\u043e-\u0431\u0435\u0441\u043f\u043b\u0430\u0442\u043d\u043e\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u044b Treepad \u0442\u0430\u043a\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b. \u041f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0443\u0437\u043b\u044b Treepad.", "Text_src": "Files from the Treepad shareware program can be imported. Only Treepad text nodes are supported." }, "format": "HEAD_PARA", "uid": "f1702858a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 XML", "Name_src": "XML Import", "Text": "TreeLine \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b XML \u043e\u0431\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430 [\u0438\u043d\u0430\u0447\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 XML]. \u042d\u0442\u043e \u043d\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0440\u0443\u0442\u0438\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 XML \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0443\u0437\u043b\u043e\u043c, \u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 XML \u2014 \u043f\u043e\u043b\u0435\u043c. \u0422\u0435\u043a\u0441\u0442\u043e\u0432\u043e\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 XML \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u0442\u0441\u044f \u0432 \u043f\u043e\u043b\u044f \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u00abElement_Data\u00bb. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 TreeLine \u043a\u0430\u043a \u0441 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u043c \u0444\u0430\u0439\u043b\u043e\u0432 XML.", "Text_src": "TreeLine will import and export generic XML files. These routines do not have much intelligence - each XML element becomes a node and each XML attribute becomes a field. XML text content become fields named \"Element_Data\". This lets TreeLine function as a crude XML editor." }, "format": "HEAD_PARA", "uid": "f1702952a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 ODF ", "Name_src": "ODF Import", "Text": "TreeLine \u043c\u043e\u0436\u0435\u0442 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u044b \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u043e\u0432 (ODF) \u0438\u0437 \u0442\u0430\u043a\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043a\u0430\u043a Apache OpenOffice \u0438 LibreOffice. \u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0443\u0437\u043b\u043e\u0432 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 \u043f\u0440\u0438\u0441\u0432\u043e\u0435\u043d\u043d\u044b\u0445 \u0432 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435 \u0441\u0442\u0438\u043b\u0435\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432. \u041b\u044e\u0431\u043e\u0439 \u0442\u0435\u043a\u0441\u0442 \u043f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u043c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0443\u0437\u043b\u0443 \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430. \u0424\u0438\u043b\u044c\u0442\u0440 \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u0442\u0435\u043a\u0441\u0442\u0430 \u0441 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439. \u0424\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044f, \u0430 \u0442\u0430\u043a\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u0430\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043d\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f.", "Text_src": "TreeLine will import Open Document Format (ODF) text documents, from applications such as Apache OpenOffice and LibreOffice. The node structure is formed based on the heading styles assigned in the document. Any text under each heading is assigned to that heading's node. The import filter is intended for simple text outlines only. No formatting is maintained, and objects such as tables and pictures are not imported." }, "format": "HEAD_PARA", "uid": "f1702a42a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043c\u043f\u043e\u0440\u0442 \u0417\u0430\u043a\u043b\u0430\u0434\u043e\u043a", "Name_src": "Bookmarks Import", "Text": "TreeLine \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0444\u0430\u0439\u043b\u044b \u0437\u0430\u043a\u043b\u0430\u0434\u043e\u043a \u043a\u0430\u043a \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Mozilla HTML (\u0431\u0440\u0430\u0443\u0437\u0435\u0440 Firefox), \u0442\u0430\u043a \u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 XBEL (\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b Konqueror, Galeon \u0438 Elinks). \u041a\u0430\u0436\u0434\u0430\u044f \u0437\u0430\u043a\u043b\u0430\u0434\u043a\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0443\u0437\u043b\u043e\u043c, \u0438\u043c\u0435\u044e\u0449\u0438\u043c \u0438\u043c\u044f \u0438 \u043f\u043e\u043b\u0435 \u0441 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u043e\u0439. \u0418\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0430\u044f\u0441\u044f \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0437\u0430\u043a\u043b\u0430\u0434\u043e\u043a, \u0442\u0430\u043a\u0430\u044f \u043a\u0430\u043a \u0434\u0430\u0442\u044b \u043f\u043e\u0441\u0435\u0449\u0435\u043d\u0438\u044f \u0438 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0438\u043a\u043e\u043d\u043a\u0438, \u043d\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442\u0441\u044f. \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0444\u0430\u0439\u043b sample_bookmarks (\u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0424\u0430\u0439\u043b > \u041e\u0442\u043a\u0440\u044b\u0442\u044c \u041f\u0440\u0438\u043c\u0435\u0440\u00bb).", "Text_src": "TreeLine will import bookmark files in both the Mozilla HTML format (Firefox browser) and the XBEL format (Konqueror, Galeon and Elinks browsers). Each bookmark becomes a node with a name and a link field. Some information in the files, such as visited dates and icon references, is not imported. For an example, see the \"sample_bookmarks\" file (by using the \"File > Open Sample\" command).
    " }, "format": "HEAD_PARA", "uid": "f1702b46a25a11e7b7c67054d2175f18" }, { "children": [ "f1702d4ea25a11e7b7c67054d2175f18", "f1702e52a25a11e7b7c67054d2175f18", "f1702f60a25a11e7b7c67054d2175f18", "65289b36b97611e783eb3417ebd53aeb", "f1703064a25a11e7b7c67054d2175f18", "f170315ea25a11e7b7c67054d2175f18", "f1703262a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0424\u0430\u0439\u043b\u043e\u0432", "Name_src": "File Export" }, "format": "HEADINGS", "uid": "f1702c4aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u0431\u0449\u0438\u0435 \u0421\u0432\u0435\u0434\u0435\u043d\u0438\u044f", "Name_src": "General Information", "Text": "\u0424\u0430\u0439\u043b\u044b \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0424\u0430\u0439\u043b > \u042d\u043a\u0441\u043f\u043e\u0440\u0442\u00bb. \u041f\u0440\u0438 \u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e \u0441 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430.", "Text_src": "Files are exported using the \"File > Export\" command. This will show a dialog box of available export types and options." }, "format": "HEAD_PARA", "uid": "f1702d4ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 HTML", "Name_src": "HTML Export", "Text": "\u041f\u043e\u0434\u0442\u0438\u043f\u044b \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0432 HTML \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0442 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u044f\u0442\u044c \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u043e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0439 \u0438\u043b\u0438 \u043c\u043d\u043e\u0433\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 HTML. \u041e\u0434\u043d\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0439 \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0432\u0441\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0432\u044b\u0432\u043e\u0434\u0430 \u0441 \u043e\u0442\u0441\u0442\u0443\u043f\u0430\u043c\u0438. \u041f\u0430\u043d\u0435\u043b\u044c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0441\u043b\u0435\u0432\u0430 \u0441 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u043d\u0430 \u043c\u0435\u0442\u043a\u0438 [\u044f\u043a\u043e\u0440\u044f] \u0432 \u043f\u043e\u0437\u0438\u0446\u0438\u044f\u0445 \u0443\u0437\u043b\u043e\u0432 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439.\n
    \n
    \n\u041f\u0440\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0435 \u0432 \u043c\u043d\u043e\u0433\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0439 HTML \u043d\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0443\u0437\u0435\u043b \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0430 \u0432\u0435\u0431-\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430. \u0412 \u0444\u0430\u0439\u043b\u044b \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u043d\u0435\u043b\u044c \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u0441\u043b\u0435\u0432\u0430 \u0441 \u0433\u0438\u043f\u0435\u0440\u0441\u0441\u044b\u043b\u043a\u0430\u043c\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0441 \u0441\u0435\u0441\u0442\u0440\u0438\u043d\u0441\u043a\u0438\u043c\u0438 \u0443\u0437\u043b\u0430\u043c\u0438, \u0443\u0437\u043b\u0430\u043c\u0438 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u0439 \u0438 \u0441\u0435\u0441\u0442\u0440\u0438\u043d\u0441\u043a\u0438\u0435 \u0443\u0437\u043b\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435\u0439.\n
    \n
    \n\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u043c\u043d\u043e\u0433\u043e\u0441\u0442\u0440\u0430\u043d\u0438\u0447\u043d\u044b\u0439 HTML \u0442\u0430\u0431\u043b\u0438\u0446 \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0444\u0430\u0439\u043b\u0435 HTML \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u043d\u0430\u0431\u043e\u0440\u0430 \u0441\u0435\u0441\u0442\u0440\u0438\u043d\u0441\u043a\u0438\u0445 \u0443\u0437\u043b\u043e\u0432, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0438 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0445 \u0443\u0437\u043b\u043e\u0432.\n
    \n
    \n\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u0418\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0414\u0435\u0440\u0435\u0432\u043e HTML \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 Javascript \u0438 CSS \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0444\u043e\u0440\u043c\u044b \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430. \u0423\u0437\u043b\u044b \u0432 \u0434\u0435\u0440\u0435\u0432\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0438 \u0441\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u0442\u044c, \u0430 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 \u043f\u0430\u043d\u0435\u043b\u0438 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432\u044b\u0445\u043e\u0434\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0443\u0437\u043b\u0430. \u041f\u0440\u0438 \u0432\u044b\u0431\u043e\u0440\u0435 \u043f\u0435\u0440\u0432\u043e\u0439 \u0444\u043e\u0440\u043c\u044b \u0442\u0430\u043a\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0441\u043e\u0437\u0434\u0430\u044e\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0430\u0439\u043b\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0441 \u0438\u043c\u0435\u044e\u0449\u0438\u043c\u0441\u044f \u0444\u0430\u0439\u043b\u043e\u043c TreeLine. \u042d\u0442\u0438 \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u044b \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0435 (\u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043e\u0431\u044b\u0447\u043d\u043e \u043f\u0440\u0435\u0434\u043e\u0442\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f). \u0412 \u0444\u0430\u0439\u043b\u0435 HTML \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u043f\u0443\u0442\u044c \u043e\u0442 \u0444\u0430\u0439\u043b\u0430 TreeLine \u043a \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u043c\u0443 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u0443 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u044d\u0442\u0430 \u0441\u0432\u044f\u0437\u044c \u0434\u043e\u043b\u0436\u043d\u0430 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0432\u0435\u0431-\u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u0414\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0437\u0430\u043c\u0435\u043d\u044f\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0444\u0430\u0439\u043b TreeLine (\u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u043d\u0435 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f).\n
    \n
    \n\u0412\u0442\u043e\u0440\u0430\u044f \u0444\u043e\u0440\u043c\u0430 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u0432 \u0418\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0435 \u0414\u0435\u0440\u0435\u0432\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043e\u0434\u0438\u043d \u0444\u0430\u0439\u043b (\u0441\u043e \u0432\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c\u0438 \u0434\u0430\u043d\u043d\u044b\u043c\u0438), \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u043c\u0443 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f \u0438\u0437 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u0435\u0431-\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u0412 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0435 \u043e\u043d\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u043f\u0435\u0440\u0432\u0430\u044f \u0444\u043e\u0440\u043c\u0430.", "Text_src": "The HTML export subtypes can export to a single page or to multiple pages. The single page export contains all of the indented output. A navigation pane on the left with links to anchors at node positions is optional.
    \n
    \nThe multiple HTML pages export has one web page per node. It includes a navigation pane on the left with links to the pages with sibling, parent and aunt/uncle nodes.
    \n
    \nMultiple HTML data tables export creates a table in each HTML file that contains the data for a set of siblings, as well as links to the parent and child pages.
    \n
    \nThe Live Tree HTML export uses Javascript and CSS to create an interactive view. Nodes in the tree can be expanded and collapsed, and a separate pane shows the output for all descendants of the selected node. The first form of this export creates separate files that are linked to the existing TreeLine file. These files are intended for use on a web server (browser security usually prevents local access). The HTML file stores the relative path from the TreeLine file to the initial export directory, so this relationship needs to be maintained on the web server. Only the TreeLine file needs to be replaced to update the data (re-export is not required).
    \n
    \nThe second form of Live Tree export creates a single file (with embedded data) that can be accessed from a local web browser. It appears the same as the first form on the browser." }, "format": "HEAD_PARA", "uid": "f1702e52a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u0422\u0435\u043a\u0441\u0442", "Name_src": "Text Export", "Text": "\u0414\u0430\u043d\u043d\u044b\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u044b \u0432 \u0442\u0430\u0431\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u0432, \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u044f\u0442\u044b\u043c\u0438 (CSV) \u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0440\u0430\u0437\u043c\u0435\u0447\u0435\u043d\u043d\u044b\u0435 \u0442\u0430\u0431\u0443\u043b\u044f\u0446\u0438\u044f\u043c\u0438. \u042d\u0442\u0438 \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0430\u043c \u0438\u043c\u043f\u043e\u0440\u0442\u0430.\n
    \n
    \n\u0418\u043c\u0435\u0435\u0442\u0441\u044f \u0442\u0430\u043a\u0436\u0435 \u044d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u043d\u0435\u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442, \u043f\u0440\u0438 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u0435\u0441\u044c \u0432\u044b\u0432\u043e\u0434 \u0432\u044b\u0433\u0440\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0431\u0435\u0437 \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u044f \u0434\u0440\u0435\u0432\u043e\u0432\u0438\u0434\u043d\u043e\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b.", "Text_src": "Data can be exported to tabbed title text, comma-delimited (CSV) tables and tab-delimited tables. These formats are the same as the corresponding import formats.\n
    \n
    \nThere is also an unformatted text export the dumps all of the output into a text file without preserving the tree structure." }, "format": "HEAD_PARA", "uid": "f1702f60a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 XML", "Name_src": "XML Export", "Text": "TreeLine \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u0442 \u0444\u0430\u0439\u043b\u044b XML \u043e\u0431\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430 [\u0438\u043d\u0430\u0447\u0435 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 XML]. \u042d\u0442\u043e \u043d\u0435 \u0432\u044b\u0441\u043e\u043a\u043e\u0438\u043d\u0442\u0435\u043b\u043b\u0435\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0440\u0443\u0442\u0438\u043d\u043d\u044b\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u2014 \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 XML \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0443\u0437\u043b\u043e\u043c, \u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0430\u0442\u0440\u0438\u0431\u0443\u0442 XML \u2014 \u043f\u043e\u043b\u0435\u043c, \u0437\u0430 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u043c \u043f\u043e\u043b\u0435\u0439 \u0441 \u0438\u043c\u0435\u043d\u0435\u043c \u00abElement_Data\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u0442\u0435\u043a\u0441\u0442 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430. \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441 TreeLine \u043a\u0430\u043a \u0441 \u043f\u0440\u0438\u043c\u0438\u0442\u0438\u0432\u043d\u044b\u043c \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u043e\u043c \u0444\u0430\u0439\u043b\u043e\u0432 XML.", "Text_src": "TreeLine will import and export generic XML files. These routines do not have much intelligence - each node becomes an XML element and each field becomes an XML attribute, except for fields named \"Element_Data\" that become the element's text. This lets TreeLine function as a crude XML editor." }, "format": "HEAD_PARA", "uid": "f1703064a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 ODF", "Name_src": "ODF Export", "Text": "\u041f\u0440\u0438 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0435 \u0432 \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0433\u043e \u0444\u043e\u0440\u043c\u0430\u0442\u0430 (ODF), \u0441\u043e\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u044b\u0439 \u0441 Apache OpenOffice \u0438 LibreOffice, TreeLine \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443. \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0443 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u043f\u0440\u0438\u0441\u0432\u0430\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u0441\u0442\u0438\u043b\u044c \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u0443\u0440\u043e\u0432\u043d\u0435. \u041b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0442\u0435\u043a\u0441\u0442 \u0432\u044b\u0432\u043e\u0434\u0430 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0443\u0437\u043b\u0430 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0442\u0435\u043a\u0441\u0442\u043e\u043c \u043f\u043e\u0434 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u043e\u043c. \u0424\u0438\u043b\u044c\u0442\u0440 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0430 \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440 \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430. \u041b\u044e\u0431\u043e\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 HTML \u0443\u0434\u0430\u043b\u044f\u0435\u0442\u0441\u044f, \u0430 \u0442\u0430\u043a\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u0430\u043a \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f.", "Text_src": "TreeLine will export an outline to an Open Document Format (ODF) text document, compatible with Apache OpenOffice and LibreOffice. The title of each node is assigned a heading style at the appropriate level. Any other text in the output of each node becomes normal text under the heading. The export filter is intended for simple text outlines only. Any HTML formatting is stripped, and objects such as tables and pictures are not supported." }, "format": "HEAD_PARA", "uid": "f170315ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0417\u0430\u043a\u043b\u0430\u0434\u043e\u043a", "Name_src": "Bookmarks Export", "Text": "TreeLine \u043c\u043e\u0436\u0435\u0442 \u044d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0437\u0430\u043a\u043b\u0430\u0434\u043e\u043a \u043a\u0430\u043a \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Mozilla HTML (\u0431\u0440\u0430\u0443\u0437\u0435\u0440 Firefox), \u0442\u0430\u043a \u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 XBEL (\u0431\u0440\u0430\u0443\u0437\u0435\u0440\u044b Konqueror, Galeon \u0438 Elinks). TreeLine \u0438\u0449\u0435\u0442 \u043f\u043e\u043b\u0435 \u0441\u0441\u044b\u043b\u043a\u0438 \u0432 \u043a\u0430\u0436\u0434\u043e\u043c \u0443\u0437\u043b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0437\u0430\u043a\u043b\u0430\u0434\u043a\u043e\u0439.", "Text_src": "TreeLine will export bookmark files in both the Mozilla HTML format (Firefox browser) and the XBEL format (Konqueror, Galeon and Elinks browsers). TreeLine will look for a link field in each node that becomes the target of the bookmark." }, "format": "HEAD_PARA", "uid": "f1703262a25a11e7b7c67054d2175f18" }, { "children": [ "f1703442a25a11e7b7c67054d2175f18", "f1703546a25a11e7b7c67054d2175f18", "f170364aa25a11e7b7c67054d2175f18", "f1703744a25a11e7b7c67054d2175f18", "9ff09734dc9011ea887bac675dac20af", "f1703848a25a11e7b7c67054d2175f18", "7e9b3b88c24511e896c7d66a6ab671cb" ], "data": { "Name": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438", "Name_src": "Customizations" }, "format": "HEADINGS", "uid": "f170335ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b", "Name_src": "Options", "Text": "\u041f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 TreeLine \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0432 \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041e\u0431\u0449\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b\u00bb. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0438\u0437 \u044d\u0442\u0438\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u0432 \u0434\u0440\u0443\u0433\u0438\u0445 \u0440\u0430\u0437\u0434\u0435\u043b\u0430\u0445 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430.", "Text_src": "TreeLine's behavior can be modified with several settings available in \"Tools > General Options\". Most of these options are covered elsewhere in this document." }, "format": "HEAD_PARA", "uid": "f1703442a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0413\u043e\u0440\u044f\u0447\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438", "Name_src": "Keyboard Shortcuts", "Text": "\u0421\u043e\u0447\u0435\u0442\u0430\u043d\u0438\u044f \u043a\u043b\u0430\u0432\u0438\u0448 [\u0433\u043e\u0440\u044f\u0447\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438] \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u044b \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u0433\u043e\u0440\u044f\u0447\u0438\u0435 \u043a\u043b\u0430\u0432\u0438\u0448\u0438\u00bb. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e, \u0432\u044b\u0431\u0440\u0430\u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0435 \u043f\u043e\u043b\u0435, \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0432\u0435\u0434\u0438\u0442\u0435 \u043d\u043e\u0432\u0443\u044e \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043a\u043b\u0430\u0432\u0438\u0448.", "Text_src": "Keyboard shortcuts can be customized by using the \"Tools > Set Keyboard Shortcuts\" command. Simply type the new key sequence with the appropriate field selected." }, "format": "HEAD_PARA", "uid": "f1703546a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041f\u0430\u043d\u0435\u043b\u0438 \u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432", "Name_src": "Toolbars", "Text": "\u0412 \u043c\u0435\u043d\u044e \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0430\u043d\u0435\u043b\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432\u00bb \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0430\u043d\u0435\u043b\u0435\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432. \u041c\u043e\u0436\u043d\u043e \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0430\u043d\u0435\u043b\u0435\u0439 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043a\u043d\u043e\u043f\u043a\u0438 \u043d\u0430 \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 \u043d\u0438\u0445.", "Text_src": "An editor to customize the toolbars is available from \"Tools > Customize Toolbars\". The number of toolbars can be set, and the buttons on each can be defined." }, "format": "HEAD_PARA", "uid": "f170364aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0428\u0440\u0438\u0444\u0442\u044b", "Name_src": "Fonts", "Text": "\u0428\u0440\u0438\u0444\u0442, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0439 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u043c\u0435\u043d\u044e \u00ab\u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b > \u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0448\u0440\u0438\u0444\u0442\u044b\u00bb. \u0422\u0430\u043a\u0436\u0435 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438 \u0438\u043c\u0435\u044e\u0442\u0441\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043b\u044f \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0448\u0440\u0438\u0444\u0442\u043e\u0432, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0445 \u0432 \u043f\u0430\u043d\u0435\u043b\u044f\u0445 \u0434\u0435\u0440\u0435\u0432\u0430, \u0432\u044b\u0432\u043e\u0434\u0430 \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440\u0430.", "Text_src": "The default font used in the application can be set using the \"Tools > Customize Fonts\" menu. There are also options to specify fonts used in the tree views, the output view and the editor views." }, "format": "HEAD_PARA", "uid": "f1703744a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0418\u043a\u043e\u043d\u043a\u0438 \u0414\u0435\u0440\u0435\u0432\u0430", "Name_src": "Tree Icons", "Text": "\u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0441 \u0438\u043a\u043e\u043d\u043a\u0430\u043c\u0438 (\u00ab~/.treeline-x.x/icons\u00bb \u0432 Linux, \u00ab\u041f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438\\<\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c >\\AppData\\roaming\\bellz\\treeline-x.x\\icons\u00bb \u0432 Windows). \u0424\u0430\u0439\u043b\u044b \u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0439 (PNG \u0438\u043b\u0438 BMP), \u043f\u043e\u043c\u0435\u0449\u0435\u043d\u043d\u044b\u0435 \u0432 \u044d\u0442\u043e\u0442 \u043a\u0430\u0442\u0430\u043b\u043e\u0433, \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0438\u043a\u043e\u043d\u043e\u043a \u0434\u0435\u0440\u0435\u0432\u0430.", "Text_src": "There is an icons directory in the user configuration directory (\"~/.treeline-x.x/icons\" on Linux, \"Users\\<user>\\AppData\\roaming\\bellz\\treeline-x.x\\icons\" on Windows). Image files (PNG or BMP) placed into this directory are available for use as tree icons." }, "format": "HEAD_PARA", "uid": "f1703848a25a11e7b7c67054d2175f18" }, { "children": [ "b5fe698830e111ebbc097054d2175f18", "7ffeb66ddc8711ea9a87ac675dac20af", "194b0533e5d811e9b5fea44cc8e97404", "db25cd62481e11e989f27054d2175f18", "800a0971305111e991cda44cc8e97404", "9c08f39ee80311e8a510a44cc8e97404", "6610203fd2c111e8b033d66a6ab671cb", "67e95a5bbbf611e891f7a44cc8e97404", "e8e10d33a14311e88e24a44cc8e97404", "4bc47248786711e8a8bfa44cc8e97404", "95a6e90a333f11e89efed66a6ab671cb", "6df9a0c5ba3b11e78e7e3417ebd53aeb", "f1703e7ea25a11e7b7c67054d2175f18", "f1704752a25a11e7b7c67054d2175f18", "f170527ea25a11e7b7c67054d2175f18", "f170652aa25a11e7b7c67054d2175f18", "f1706be2a25a11e7b7c67054d2175f18", "f170748ea25a11e7b7c67054d2175f18", "f1708032a25a11e7b7c67054d2175f18", "f1708ae6a25a11e7b7c67054d2175f18", "f170ab34a25a11e7b7c67054d2175f18", "f170c1aaa25a11e7b7c67054d2175f18", "f170e900a25a11e7b7c67054d2175f18", "f170fddca25a11e7b7c67054d2175f18", "f1710e58a25a11e7b7c67054d2175f18", "f1711f24a25a11e7b7c67054d2175f18" ], "data": { "Name": "\u0418\u0441\u0442\u043e\u0440\u0438\u044f \u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439", "Name_src": "Revision History" }, "format": "HEADINGS", "uid": "f1703d8ea25a11e7b7c67054d2175f18" }, { "children": [ "f1703f8ca25a11e7b7c67054d2175f18", "f170427aa25a11e7b7c67054d2175f18" ], "data": { "Name": "March 26, 2017 - Release 2.1.2 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1703e7ea25a11e7b7c67054d2175f18" }, { "children": [ "f170407ca25a11e7b7c67054d2175f18", "f1704176a25a11e7b7c67054d2175f18" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "f1703f8ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It may contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) should probably be used for critical work." }, "format": "BULLETS", "uid": "f170407ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations have not yet been updated." }, "format": "BULLETS", "uid": "f1704176a25a11e7b7c67054d2175f18" }, { "children": [ "f1704360a25a11e7b7c67054d2175f18", "f170445aa25a11e7b7c67054d2175f18", "f1704554a25a11e7b7c67054d2175f18", "f170464ea25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170427aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "DateTime output", "Text": "Fix problems formatting DateTime fields in output views." }, "format": "BULLETS", "uid": "f1704360a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Internal links", "Text": "Fix dialog issues with clicking on targets when creating inline internal links." }, "format": "BULLETS", "uid": "f170445aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data view tabbing", "Text": "Fix a regression that prevented using the tab key to cycle between data edit view items." }, "format": "BULLETS", "uid": "f1704554a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Autosave restore", "Text": "Avoid opening two windows when restoring an auto-saved backup file." }, "format": "BULLETS", "uid": "f170464ea25a11e7b7c67054d2175f18" }, { "children": [ "f1704842a25a11e7b7c67054d2175f18", "f1704b30a25a11e7b7c67054d2175f18", "f1704d1aa25a11e7b7c67054d2175f18" ], "data": { "Name": "March 12, 2017 - Release 2.1.1 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1704752a25a11e7b7c67054d2175f18" }, { "children": [ "f1704928a25a11e7b7c67054d2175f18", "f1704a2ca25a11e7b7c67054d2175f18" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "f1704842a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It may contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) should probably be used for critical work." }, "format": "BULLETS", "uid": "f1704928a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations have not yet been updated." }, "format": "BULLETS", "uid": "f1704a2ca25a11e7b7c67054d2175f18" }, { "children": [ "f1704c20a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1704b30a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Windows binary", "Text": "The Windows binary is now built using Python 3.6 and PyQt 5.8." }, "format": "BULLETS", "uid": "f1704c20a25a11e7b7c67054d2175f18" }, { "children": [ "f1704f54a25a11e7b7c67054d2175f18", "f170506ca25a11e7b7c67054d2175f18", "f1705166a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1704d1aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Set icon crash", "Text": "Fix a crash when changing the icon on the Type Config page of the Configure Data Types dialog box." }, "format": "BULLETS", "uid": "f1704f54a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Type list issues", "Text": "Fix inconsistent type selections on the Type List page of the Configure Data Types dialog box." }, "format": "BULLETS", "uid": "f170506ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Window placement", "Text": "Fix issues with restoring the placement of the TreeLine window in some multiple monitor setups." }, "format": "BULLETS", "uid": "f1705166a25a11e7b7c67054d2175f18" }, { "children": [ "f170536ea25a11e7b7c67054d2175f18", "f170565ca25a11e7b7c67054d2175f18", "f170603ea25a11e7b7c67054d2175f18", "f1706228a25a11e7b7c67054d2175f18" ], "data": { "Name": "February 20, 2017 - Release 2.1.0 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170527ea25a11e7b7c67054d2175f18" }, { "children": [ "f170545ea25a11e7b7c67054d2175f18", "f1705558a25a11e7b7c67054d2175f18" ], "data": { "Name": "Notes" }, "format": "BULLET_HEADING", "uid": "f170536ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unstable snapshot", "Text": "This is an unstable development snapshot of TreeLine. It probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) should probably be used for critical work." }, "format": "BULLETS", "uid": "f170545ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "The GUI and documentation translations have not yet been updated." }, "format": "BULLETS", "uid": "f1705558a25a11e7b7c67054d2175f18" }, { "children": [ "f170574ca25a11e7b7c67054d2175f18", "f1705850a25a11e7b7c67054d2175f18", "f1705954a25a11e7b7c67054d2175f18", "f1705a4ea25a11e7b7c67054d2175f18", "f1705b48a25a11e7b7c67054d2175f18", "f1705c4ca25a11e7b7c67054d2175f18", "f1705d46a25a11e7b7c67054d2175f18", "f1705e40a25a11e7b7c67054d2175f18", "f1705f3aa25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170565ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Port to Qt5", "Text": "TreeLine has been ported from the Qt4 library to the Qt5 library. The system requirements have been updated to Python 3.4 or higher, PyQt 5.4 or higher and Qt 5.4 or higher." }, "format": "BULLETS", "uid": "f170574ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Cloned nodes", "Text": "Cloned nodes that can duplicate sections of the tree have been added. Editing their data or child structure in one location changes all locations. They are created by copying nodes and then using the \"Edit->Paste Cloned Node\" command to paste them elsewhere. The clone link can be removed by deleting the nodes or by cutting them and pasting them back using the regular paste command." }, "format": "BULLETS", "uid": "f1705850a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "DateTime field", "Text": "Added a new DateTime field that combines dates and times into a single field that is useful for timestamps. The editor format is a combination of the date and time formats from the general options, separated by a space." }, "format": "BULLETS", "uid": "f1705954a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML in choice fields", "Text": "Added an option to allow HTML tags in Choice, AutoChoice, Combination, AutoCombination and RegularExpression fields. The control is in the Field Config tab of the Configure Data Types dialog. This option is disabled by default. If enabled, special characters (angled brackets and quotation marks) will need to be escaped to show up in text." }, "format": "BULLETS", "uid": "f1705a4ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved conditional rules", "Text": "Saved rules for Conditional Find and Conditional Filter commands are listed directly in the dialog boxes, making them easier to load and save." }, "format": "BULLETS", "uid": "f1705b48a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "CSV import/export", "Text": "Added comma-delimited (CSV) table import and export, similar to existing tab-delimited table import and export. The export only handles data from a single level of child nodes." }, "format": "BULLETS", "uid": "f1705c4ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Incremental title search", "Text": "Added a quick, incremental search of node titles. By default, it's bound to ctrl+/. Then, matching titles are found as the search string is typed. The F3 and shift+F3 keys can be used to go to the next or previous matches, respectively." }, "format": "BULLETS", "uid": "f1705d46a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Multiple field selection", "Text": "Multiple fields can now be selected in the Output page of the Configuration dialog, so several fields can be added to the formats simultaneously." }, "format": "BULLETS", "uid": "f1705e40a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Print settings", "Text": "A pull-down selector for printers has been added to the Print Setup dialog. This enables TreeLine to verify that the page size and margin settings are supported by the current printer." }, "format": "BULLETS", "uid": "f1705f3aa25a11e7b7c67054d2175f18" }, { "children": [ "f170612ea25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170603ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "SpacedText Field special characters", "Text": "The SpacedText Field now allows special HTML characters (angled brackets and quotation marks) without requiring them to be manually escaped." }, "format": "BULLETS", "uid": "f170612ea25a11e7b7c67054d2175f18" }, { "children": [ "f170630ea25a11e7b7c67054d2175f18", "f1706426a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1706228a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Printed page splits", "Text": "The code that splits content into pages when printing has been improved. It now handles very long nodes better." }, "format": "BULLETS", "uid": "f170630ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Formatted field title edits", "Text": "When formatted fields (dates, times, etc.) are used in node titles, editing the titles in the tree or in the Title List pane will now work if the edit and output formats are similar." }, "format": "BULLETS", "uid": "f1706426a25a11e7b7c67054d2175f18" }, { "children": [ "f1706610a25a11e7b7c67054d2175f18", "f1706804a25a11e7b7c67054d2175f18" ], "data": { "Name": "October 3, 2015 - Release 2.0.2 (new stable release)" }, "format": "HEADINGS", "uid": "f170652aa25a11e7b7c67054d2175f18" }, { "children": [ "f1706700a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1706610a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data edit regression", "Text": "Fixed a major regression in 2.0.1 that broke data editors for most specialized field types (number, math, boolean, choice, etc.)" }, "format": "BULLETS", "uid": "f1706700a25a11e7b7c67054d2175f18" }, { "children": [ "f17068f4a25a11e7b7c67054d2175f18", "f17069e4a25a11e7b7c67054d2175f18", "f1706ae8a25a11e7b7c67054d2175f18" ], "data": { "Name": "Compatibility Notes" }, "format": "BULLET_HEADING", "uid": "f1706804a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File format", "Text": "There are some file format changes between TreeLine 1.4.x and this version of TreeLine." }, "format": "BULLETS", "uid": "f17068f4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File conversion", "Text": "Older files opened in this version are automatically converted when saved." }, "format": "BULLETS", "uid": "f17069e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File compatibility", "Text": "Files saved in this version may not be fully compatible with TreeLine 1.4.x." }, "format": "BULLETS", "uid": "f1706ae8a25a11e7b7c67054d2175f18" }, { "children": [ "f1706cd2a25a11e7b7c67054d2175f18", "f1706fb6a25a11e7b7c67054d2175f18" ], "data": { "Name": "September 26, 2015 - Release 2.0.1 (new stable release)" }, "format": "HEADINGS", "uid": "f1706be2a25a11e7b7c67054d2175f18" }, { "children": [ "f1706db8a25a11e7b7c67054d2175f18", "f1706ebca25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1706cd2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Plugin options", "Text": "Added methods to the plugin interface that allow general program options to be queried and changed." }, "format": "BULLETS", "uid": "f1706db8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Table import errors", "Text": "Improve text table import error messages by including the line number where the problem is found." }, "format": "BULLETS", "uid": "f1706ebca25a11e7b7c67054d2175f18" }, { "children": [ "f170709ca25a11e7b7c67054d2175f18", "f1707196a25a11e7b7c67054d2175f18", "f1707290a25a11e7b7c67054d2175f18", "f1707380a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1706fb6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data edit undo", "Text": "Reduce the amount of work that a single undo command removes from editors in the data edit view." }, "format": "BULLETS", "uid": "f170709ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Configuration changes", "Text": "Fixed a bug that prevented setting the unique ID reference field on a newly created data type." }, "format": "BULLETS", "uid": "f1707196a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Legacy newline convert", "Text": "Preserve hard newlines in text fields when converting TreeLine 1.4.x files to this version." }, "format": "BULLETS", "uid": "f1707290a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Indent expand status", "Text": "Fix problems preserving expand/collapse node states when indenting and unindenting nodes." }, "format": "BULLETS", "uid": "f1707380a25a11e7b7c67054d2175f18" }, { "children": [ "f1707592a25a11e7b7c67054d2175f18", "f1707c5ea25a11e7b7c67054d2175f18" ], "data": { "Name": "May 17, 2015 - Release 2.0.0 (new stable release)" }, "format": "HEADINGS", "uid": "f170748ea25a11e7b7c67054d2175f18" }, { "children": [ "f1707682a25a11e7b7c67054d2175f18", "f170777ca25a11e7b7c67054d2175f18", "f1707876a25a11e7b7c67054d2175f18", "f1707966a25a11e7b7c67054d2175f18", "f1707a60a25a11e7b7c67054d2175f18", "f1707b5aa25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1707592a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Treepad import update", "Text": "Modified the Treepad file import to use SpacedText fields to more closely match Treepad formatting." }, "format": "BULLETS", "uid": "f1707682a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Treepad export", "Text": "An optional plugin was written that can export files to the Treepad text file format." }, "format": "BULLETS", "uid": "f170777ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "New icon", "Text": "The TreeLine icon was replaced with a new one. Thanks to David Reimer for contributing the artwork." }, "format": "BULLETS", "uid": "f1707876a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Translation updates", "Text": "The German and Portuguese GUI translations were updated." }, "format": "BULLETS", "uid": "f1707966a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sample file updates", "Text": "Updated the long text sample file to include the SpacedText field type, and added a conditional equation to the math sample file." }, "format": "BULLETS", "uid": "f1707a60a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Documentation update", "Text": "Updated the Math Field section of the documentation." }, "format": "BULLETS", "uid": "f1707b5aa25a11e7b7c67054d2175f18" }, { "children": [ "f1707d44a25a11e7b7c67054d2175f18", "f1707e3ea25a11e7b7c67054d2175f18", "f1707f38a25a11e7b7c67054d2175f18" ], "data": { "Name": "Compatibility Notes" }, "format": "BULLET_HEADING", "uid": "f1707c5ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File format", "Text": "There are some file format changes between TreeLine 1.4.x and this version of TreeLine." }, "format": "BULLETS", "uid": "f1707d44a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File conversion", "Text": "Older files opened in this version are automatically converted when saved." }, "format": "BULLETS", "uid": "f1707e3ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File compatibility", "Text": "Files saved in this version may not be fully compatible with TreeLine 1.4.x." }, "format": "BULLETS", "uid": "f1707f38a25a11e7b7c67054d2175f18" }, { "children": [ "f1708118a25a11e7b7c67054d2175f18", "f17083fca25a11e7b7c67054d2175f18", "f1708802a25a11e7b7c67054d2175f18" ], "data": { "Name": "March 29, 2015 - Release 1.9.7 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1708032a25a11e7b7c67054d2175f18" }, { "children": [ "f1708208a25a11e7b7c67054d2175f18", "f1708302a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f1708118a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field conditions", "Text": "Added comparison operators and conditional if statements to math field equations. The operators can be used with a new boolean result type, or as a part of numeric, date, time or text expressions." }, "format": "BULLETS", "uid": "f1708208a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field text operations", "Text": "Text operators were made available in math field equations, and the result type can be set to text. This allows math fields to combine text from other fields, replace sub-strings and change capitalization." }, "format": "BULLETS", "uid": "f1708302a25a11e7b7c67054d2175f18" }, { "children": [ "f17084eca25a11e7b7c67054d2175f18", "f17085f0a25a11e7b7c67054d2175f18", "f17086fea25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f17083fca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved status bar message", "Text": "Added a \"file saved\" status bar message." }, "format": "BULLETS", "uid": "f17084eca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "German translation", "Text": "Added a German GUI translation." }, "format": "BULLETS", "uid": "f17085f0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Portuguese translation", "Text": "Updated the Portuguese GUI translation." }, "format": "BULLETS", "uid": "f17086fea25a11e7b7c67054d2175f18" }, { "children": [ "f17088e8a25a11e7b7c67054d2175f18", "f17089e2a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f1708802a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Combination editor", "Text": "Fixed a focus problem that made Combination and AutoCombination field editor pull-downs unusable." }, "format": "BULLETS", "uid": "f17088e8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Choice editor", "Text": "Fixed a focus problem that made the pull-downs in choice and boolean field editors unusable on Linux." }, "format": "BULLETS", "uid": "f17089e2a25a11e7b7c67054d2175f18" }, { "children": [ "f1708bcca25a11e7b7c67054d2175f18", "f17097aca25a11e7b7c67054d2175f18", "f170a2eca25a11e7b7c67054d2175f18" ], "data": { "Name": "March 10, 2015 - Release 1.9.6 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1708ae6a25a11e7b7c67054d2175f18" }, { "children": [ "f1708cbca25a11e7b7c67054d2175f18", "f1708db6a25a11e7b7c67054d2175f18", "f1708ea6a25a11e7b7c67054d2175f18", "f1708faaa25a11e7b7c67054d2175f18", "f17090aea25a11e7b7c67054d2175f18", "f17091e4a25a11e7b7c67054d2175f18", "f17092dea25a11e7b7c67054d2175f18", "f1709644a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f1708bcca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "OneLineText field", "Text": "Added a new OneLineText field type that restricts the text length to a single line." }, "format": "BULLETS", "uid": "f1708cbca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "All Types conditional test", "Text": "Added an All Types option to the conditional find and filter commands. This allows multiple node types to be found or filtered at the same time. The fields from every type are available for use in conditions. The conditions give a false result for all node types that do not contain that field name." }, "format": "BULLETS", "uid": "f1708db6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field dates and times", "Text": "Added support for date and time calculations using math fields. Math equation result types can be set to numeric, date or time output. Date fields can be subtracted to give the number of days elapsed, and numbers of days can be added to or subtracted from dates, resulting in new dates. Time fields can be subtracted to give the number of seconds elapsed, and numbers of seconds can be added to or subtracted from times, resulting in new times." }, "format": "BULLETS", "uid": "f1708ea6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field root references", "Text": "In math fields, added an equation reference level to reference fields in the root node. This provides a place for \"constant\" field values that can be referenced from any node but only need to be changed in one location." }, "format": "BULLETS", "uid": "f1708faaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Plugin interface", "Text": "Support was added for plugin extension modules. Most of the interface methods from TreeLine 1.4.x were duplicated to ease porting of old plugins. Of course, old plugins must be ported from Python 2.x to Python 3.x, and there are multi-window implementation differences. New interfaces allow the creation of new field types and the execution of any menu command. Sample plugins are available on the TreeLine download page." }, "format": "BULLETS", "uid": "f17090aea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Automatic HTML tags", "Text": "Added text formatting and link commands for HTML fields that add tags to the HTML content." }, "format": "BULLETS", "uid": "f17091e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Open in folder", "Text": "An open in folder command was added to external link field editors to open the directory in a file manager." }, "format": "BULLETS", "uid": "f17092dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Select All command", "Text": "Added the Select All command to global menus with a different default shortcut key (ctrl-L) to avoid conflicts with the add child shortcut." }, "format": "BULLETS", "uid": "f1709644a25a11e7b7c67054d2175f18" }, { "children": [ "f170989ca25a11e7b7c67054d2175f18", "f170998ca25a11e7b7c67054d2175f18", "f1709a7ca25a11e7b7c67054d2175f18", "f1709b8aa25a11e7b7c67054d2175f18", "f1709c7aa25a11e7b7c67054d2175f18", "f1709d6aa25a11e7b7c67054d2175f18", "f1709e50a25a11e7b7c67054d2175f18", "f1709f40a25a11e7b7c67054d2175f18", "f170a026a25a11e7b7c67054d2175f18", "f170a116a25a11e7b7c67054d2175f18", "f170a206a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f17097aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data edit view focus", "Text": "Improved the focus handling for data edit view edit boxes. This eliminates the blue outline for boxes in inactive data edit views. It also makes tab-to-focus more predictable, including fully selecting single-line field types when they receive tab focus." }, "format": "BULLETS", "uid": "f170989ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Data editor resize", "Text": "Data edit boxes are now automatically resized when editing is complete and the focus moves to another row." }, "format": "BULLETS", "uid": "f170998ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drag external links", "Text": "Allow files to be drag & dropped on data edit boxes to create external links." }, "format": "BULLETS", "uid": "f1709a7ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Stay-on-top dialogs", "Text": "Small, non-modal dialogs, such as those for sorting, numbering, finding and filtering, have been set to stay on top, so they won't be obscured by TreeLine windows." }, "format": "BULLETS", "uid": "f1709b8aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Opening external links", "Text": "Made opening associated programs from external file links more consistent, especially in Linux." }, "format": "BULLETS", "uid": "f1709c7aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Copy types from file", "Text": "The copy types from file command now supports encrypted and compressed files." }, "format": "BULLETS", "uid": "f1709d6aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Wait cursors", "Text": "Added wait cursors to TreeLine operations that could be time consuming." }, "format": "BULLETS", "uid": "f1709e50a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Context menus", "Text": "Improved the consistency of context menus and shortcut commands used in edit boxes." }, "format": "BULLETS", "uid": "f1709f40a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Portuguese translation", "Text": "Added a nearly complete Portuguese GUI translation." }, "format": "BULLETS", "uid": "f170a026a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sample file languages", "Text": "Added support for sample TreeLine files to be provided in alternate languages." }, "format": "BULLETS", "uid": "f170a116a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Documentation translation", "Text": "Prepared the help file for translation into other languages," }, "format": "BULLETS", "uid": "f170a206a25a11e7b7c67054d2175f18" }, { "children": [ "f170a3d2a25a11e7b7c67054d2175f18", "f170a4b8a25a11e7b7c67054d2175f18", "f170a5a8a25a11e7b7c67054d2175f18", "f170a698a25a11e7b7c67054d2175f18", "f170a77ea25a11e7b7c67054d2175f18", "f170a86ea25a11e7b7c67054d2175f18", "f170a95ea25a11e7b7c67054d2175f18", "f170aa44a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170a2eca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Duplicate unique IDs", "Text": "Corrupted TreeLine files with the same unique ID assigned to multiple nodes no longer fail to open. The user is warned that unique IDs have been updated, which could break some internal links." }, "format": "BULLETS", "uid": "f170a3d2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional field list", "Text": "Fixed missing fields in the pull-down list in the conditional find and filter dialog boxes when a rule was re-used after a node type change. " }, "format": "BULLETS", "uid": "f170a4b8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field missing references", "Text": "Fixed problems with math fields that reference non-existing fields in parent or child nodes." }, "format": "BULLETS", "uid": "f170a5a8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field type updates", "Text": "Made math fields update properly after node type changes." }, "format": "BULLETS", "uid": "f170a698a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Rename bullet/table fields", "Text": "Fixed inconsistent updates after renaming fields used with bulleted or tabled output." }, "format": "BULLETS", "uid": "f170a77ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Copying descendants", "Text": "Made node copy-paste and drag-and-drop work when the initial selection includes both parent and child nodes. " }, "format": "BULLETS", "uid": "f170a86ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Tabbed text import", "Text": "When importing a tabbed text file with multiple top-level nodes, create a single higher-level node to prevent failure." }, "format": "BULLETS", "uid": "f170a95ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Custom toolbar dialog", "Text": "Fixed the availability of the move up button in the customize toolbar dialog when the second command in the list is selected." }, "format": "BULLETS", "uid": "f170aa44a25a11e7b7c67054d2175f18" }, { "children": [ "f170ac38a25a11e7b7c67054d2175f18", "f170afeea25a11e7b7c67054d2175f18", "f170b836a25a11e7b7c67054d2175f18" ], "data": { "Name": "December 31, 2014 - Release 1.9.5 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170ab34a25a11e7b7c67054d2175f18" }, { "children": [ "f170ad1ea25a11e7b7c67054d2175f18", "f170ae0ea25a11e7b7c67054d2175f18", "f170aefea25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170ac38a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Math field type", "Text": "Added a math field type that is configured by defining an equation. The field value is automatically calculated based on references to numerical values in other nodes. See the \"sample_math_fields\" file for a usage example." }, "format": "BULLETS", "uid": "f170ad1ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Clear formatting", "Text": "Added a Clear Formatting command that removes font changes and links from data editor text." }, "format": "BULLETS", "uid": "f170ae0ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "GUI Translations", "Text": "Made source code changes necessary to support user interface translations into other languages. The actual translation work remains to be done." }, "format": "BULLETS", "uid": "f170aefea25a11e7b7c67054d2175f18" }, { "children": [ "f170b0caa25a11e7b7c67054d2175f18", "f170b1baa25a11e7b7c67054d2175f18", "f170b2aaa25a11e7b7c67054d2175f18", "f170b390a25a11e7b7c67054d2175f18", "f170b480a25a11e7b7c67054d2175f18", "f170b570a25a11e7b7c67054d2175f18", "f170b656a25a11e7b7c67054d2175f18", "f170b746a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170afeea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Combination field scroll bars", "Text": "Add scroll bars to the pull-down editors for combination fields with many entries." }, "format": "BULLETS", "uid": "f170b0caa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "External link truncation", "Text": "Reduce the truncation of external link URLs when generating default display names." }, "format": "BULLETS", "uid": "f170b1baa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "File newlines", "Text": "Use Unix-style newlines for saved TreeLine files to keep files consistent across platforms." }, "format": "BULLETS", "uid": "f170b2aaa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML panes", "Text": "Update the CSS code in exported HTML with navigation panes to improve the appearance in some browsers." }, "format": "BULLETS", "uid": "f170b390a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Undo optimization", "Text": "Optimize some undo information to reduce the amount of data in memory." }, "format": "BULLETS", "uid": "f170b480a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Move sample files", "Text": "Move sample files into a separate directory to avoid future translation conflicts." }, "format": "BULLETS", "uid": "f170b570a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Installer clarification", "Text": "Clarify a Linux installer error message when checking for the Python 3 version of PyQt." }, "format": "BULLETS", "uid": "f170b656a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Include MSVC files", "Text": "Include MSVCR DLL files in the Windows installer." }, "format": "BULLETS", "uid": "f170b746a25a11e7b7c67054d2175f18" }, { "children": [ "f170b91ca25a11e7b7c67054d2175f18", "f170ba0ca25a11e7b7c67054d2175f18", "f170baf2a25a11e7b7c67054d2175f18", "f170bbeca25a11e7b7c67054d2175f18", "f170bcf0a25a11e7b7c67054d2175f18", "f170bde0a25a11e7b7c67054d2175f18", "f170bed0a25a11e7b7c67054d2175f18", "f170bfc0a25a11e7b7c67054d2175f18", "f170c0a6a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170b836a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Applying config dialog settings", "Text": "Fix problems applying multiple configuration changes while the Configure Data Types dialog box remains open." }, "format": "BULLETS", "uid": "f170b91ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Title list line split", "Text": "In the Title List editor, splitting a title into two lines now creates a new node without losing the children and parameters of the original node." }, "format": "BULLETS", "uid": "f170ba0ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Title list undo", "Text": "Fix the undo command in the Title List View so that deleted lines/nodes are properly restored. " }, "format": "BULLETS", "uid": "f170baf2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Sorting by fields", "Text": "When sorting nodes by fields, properly handle a reverse direction." }, "format": "BULLETS", "uid": "f170bbeca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Find and replace", "Text": "Fix problems with the find and replace command when a particular node type is specified." }, "format": "BULLETS", "uid": "f170bcf0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional types", "Text": "Fix problems defining conditional types from the Configure Data Types dialog box." }, "format": "BULLETS", "uid": "f170bde0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Apply font sizes", "Text": "Correctly apply font size formatting to selections with mixed font sizes." }, "format": "BULLETS", "uid": "f170bed0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Editor height", "Text": "Fix the height of long text field editors with customized data editor fonts." }, "format": "BULLETS", "uid": "f170bfc0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Base 64 image export", "Text": "Fix HTML export of Base 64 images." }, "format": "BULLETS", "uid": "f170c0a6a25a11e7b7c67054d2175f18" }, { "children": [ "f170c286a25a11e7b7c67054d2175f18", "f170e068a25a11e7b7c67054d2175f18", "f170e46ea25a11e7b7c67054d2175f18" ], "data": { "Name": "March 8, 2014 - Release 1.9.4 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170c1aaa25a11e7b7c67054d2175f18" }, { "children": [ "f170d8d4a25a11e7b7c67054d2175f18", "f170d9d8a25a11e7b7c67054d2175f18", "f170dac8a25a11e7b7c67054d2175f18", "f170dbb8a25a11e7b7c67054d2175f18", "f170dca8a25a11e7b7c67054d2175f18", "f170dd98a25a11e7b7c67054d2175f18", "f170de88a25a11e7b7c67054d2175f18", "f170df6ea25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170c286a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Documentation", "Text": "Created new documentation, including a TreeLine file with details and a text file with basic usage instructions. Both are accessible from the help menu." }, "format": "BULLETS", "uid": "f170d8d4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Font settings", "Text": "Added customizing of default fonts used in the tree, output and editor views." }, "format": "BULLETS", "uid": "f170d9d8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spaced text field", "Text": "Added a new SpacedText field type that holds plain text and preserves all spacing." }, "format": "BULLETS", "uid": "f170dac8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Combination editor", "Text": "Combination and auto combination field types now use a simpler checkbox style pull-down editor." }, "format": "BULLETS", "uid": "f170dbb8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Autosave option", "Text": "An autosave option was added." }, "format": "BULLETS", "uid": "f170dca8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unique ID output", "Text": "A unique ID reference field was added to the file info fields to allow node unique IDs to be included in output formats." }, "format": "BULLETS", "uid": "f170dd98a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Paste plain text", "Text": "A plain text paste command was added to paste non-formatted text to data editors." }, "format": "BULLETS", "uid": "f170de88a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Indent option", "Text": "Added an option to set the child indent offset amount." }, "format": "BULLETS", "uid": "f170df6ea25a11e7b7c67054d2175f18" }, { "children": [ "f170e162a25a11e7b7c67054d2175f18", "f170e252a25a11e7b7c67054d2175f18", "f170e36aa25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170e068a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Print preview size", "Text": "The last size and position of the print preview window are remembered and restored." }, "format": "BULLETS", "uid": "f170e162a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Page breaks in nodes", "Text": "When printing, nodes with long text content are split between pages." }, "format": "BULLETS", "uid": "f170e252a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Export relative links", "Text": "In multiple page HTML exports, relative links in the content are adjusted based on the directory depth." }, "format": "BULLETS", "uid": "f170e36aa25a11e7b7c67054d2175f18" }, { "children": [ "f170e54aa25a11e7b7c67054d2175f18", "f170e63aa25a11e7b7c67054d2175f18", "f170e720a25a11e7b7c67054d2175f18", "f170e810a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170e46ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Blank nodes", "Text": "Fixed problems outputting completely blank nodes." }, "format": "BULLETS", "uid": "f170e54aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional rules", "Text": "Problems with the contains and true/false conditional rules were fixed." }, "format": "BULLETS", "uid": "f170e63aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Link dialogs", "Text": "Fixed issues displaying several editor link dialogs in quick succession." }, "format": "BULLETS", "uid": "f170e720a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Output config cursor", "Text": "In the configure data types dialog, the output format cursor no longer moves when switching to other field references." }, "format": "BULLETS", "uid": "f170e810a25a11e7b7c67054d2175f18" }, { "children": [ "f170e9dca25a11e7b7c67054d2175f18", "f170f12aa25a11e7b7c67054d2175f18", "f170f846a25a11e7b7c67054d2175f18" ], "data": { "Name": "January 19, 2014 - Release 1.9.3 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170e900a25a11e7b7c67054d2175f18" }, { "children": [ "f170eac2a25a11e7b7c67054d2175f18", "f170eba8a25a11e7b7c67054d2175f18", "f170ec8ea25a11e7b7c67054d2175f18", "f170ed74a25a11e7b7c67054d2175f18", "f170ee5aa25a11e7b7c67054d2175f18", "f170ef4aa25a11e7b7c67054d2175f18", "f170f030a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170e9dca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Keyboard shortcuts", "Text": "Added controls in the Tools menu for customizing TreeLine's keyboard shortcuts." }, "format": "BULLETS", "uid": "f170eac2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Toolbars", "Text": "Controls for customizing TreeLine's toolbar buttons were added to the Tools menu." }, "format": "BULLETS", "uid": "f170eba8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional search", "Text": "New dialogs were created for conditional finding and filtering of nodes. Specific conditions can be applied to individual types and fields, and the conditions can be saved." }, "format": "BULLETS", "uid": "f170ec8ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Find and replace", "Text": "Find and replace functionality was added to search and change nodes' text data. The search can be limited to specific types and fields." }, "format": "BULLETS", "uid": "f170ed74a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Table output", "Text": "A new option for output data in tables was added to the Type Config pane of the Configure Data Types dialog. Each line of the output format becomes a column. Any text at the start of the format line that is followed by a colon becomes a table heading." }, "format": "BULLETS", "uid": "f170ee5aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Bullet output", "Text": "An option to add bullets to the output of child nodes was added to the Type Config pane of the Configure Data Types dialog." }, "format": "BULLETS", "uid": "f170ef4aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Toggle selections", "Text": "Added View > Previous Selection and Next Selection commands to step through the node selection history." }, "format": "BULLETS", "uid": "f170f030a25a11e7b7c67054d2175f18" }, { "children": [ "f170f210a25a11e7b7c67054d2175f18", "f170f2f6a25a11e7b7c67054d2175f18", "f170f418a25a11e7b7c67054d2175f18", "f170f4fea25a11e7b7c67054d2175f18", "f170f5e4a25a11e7b7c67054d2175f18", "f170f6d4a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f170f12aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drop to reorder", "Text": "Nodes can now be reordered by dragging and dropping them between sibling nodes." }, "format": "BULLETS", "uid": "f170f210a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Date entry formats", "Text": "The keyboard entry of dates and times into fields was made more flexible by allowing entries such as 4-digit years that don't exactly match the entry format." }, "format": "BULLETS", "uid": "f170f2f6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Default link names", "Text": "Any text selection is now used as the default name for links inserted into text fields." }, "format": "BULLETS", "uid": "f170f418a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Anchor links", "Text": "Links to local named anchors in a node's HTML text content now work if they don't conflict with any node unique IDs." }, "format": "BULLETS", "uid": "f170f4fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Line spacing", "Text": "Line spacing in output views was made more consistent." }, "format": "BULLETS", "uid": "f170f5e4a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved states", "Text": "Improved the efficiency of restoring node open/close states when opening files." }, "format": "BULLETS", "uid": "f170f6d4a25a11e7b7c67054d2175f18" }, { "children": [ "f170f936a25a11e7b7c67054d2175f18", "f170fa1ca25a11e7b7c67054d2175f18", "f170fb0ca25a11e7b7c67054d2175f18", "f170fbf2a25a11e7b7c67054d2175f18", "f170fce2a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f170f846a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Paste font sizes", "Text": "Errors when pasting text with varying font sizes into data editors were fixed." }, "format": "BULLETS", "uid": "f170f936a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional data types", "Text": "Various issues with conditional data types were fixed, including problems with pasting conditional nodes and prompt updating when the types change." }, "format": "BULLETS", "uid": "f170fa1ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drag undo", "Text": "Problems with undoing the dragging and dropping of a node were fixed." }, "format": "BULLETS", "uid": "f170fb0ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Expand branches", "Text": "Fix the extremely slow operation of the View > Expand Full Branch and Collapse Full Branch commands." }, "format": "BULLETS", "uid": "f170fbf2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Printed lines", "Text": "Fix improperly placed branch lines in printed output." }, "format": "BULLETS", "uid": "f170fce2a25a11e7b7c67054d2175f18" }, { "children": [ "f170fec2a25a11e7b7c67054d2175f18", "f171053ea25a11e7b7c67054d2175f18", "f17108e0a25a11e7b7c67054d2175f18" ], "data": { "Name": "October 22, 2013 - Release 1.9.2 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f170fddca25a11e7b7c67054d2175f18" }, { "children": [ "f170ffa8a25a11e7b7c67054d2175f18", "f171008ea25a11e7b7c67054d2175f18", "f171017ea25a11e7b7c67054d2175f18", "f1710264a25a11e7b7c67054d2175f18", "f171034aa25a11e7b7c67054d2175f18", "f1710430a25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f170fec2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Spell check", "Text": "Added a spell check tool. This requires either aspell, ispell or hunspell to be installed." }, "format": "BULLETS", "uid": "f170ffa8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Numbering field type", "Text": "Included a node numbering field type with several formatting options. An update numbering command fills in the sequence." }, "format": "BULLETS", "uid": "f171008ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Add category level", "Text": "Added a command to add a category level based on a subset of data fields." }, "format": "BULLETS", "uid": "f171017ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Flatten by category", "Text": "Added a flatten by category command to combine parent fields into child nodes." }, "format": "BULLETS", "uid": "f1710264a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Flatten by link", "Text": "A new flatten by link command flattens the structure and provides internal links to the former parent nodes." }, "format": "BULLETS", "uid": "f171034aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Arrange by link", "Text": "An arrange by link command restores the structure based on parent internal links." }, "format": "BULLETS", "uid": "f1710430a25a11e7b7c67054d2175f18" }, { "children": [ "f171061aa25a11e7b7c67054d2175f18", "f171070aa25a11e7b7c67054d2175f18", "f17107f0a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f171053ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "URL drag-and-drop", "Text": "Allow file URL drag-and-drop on active external link data edit widgets." }, "format": "BULLETS", "uid": "f171061aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Share directory", "Text": "Change the Linux installer to use the 'share' directory in place of 'lib' for python files." }, "format": "BULLETS", "uid": "f171070aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Windows binary", "Text": "Update the Windows binary to use version 3.3 of Python." }, "format": "BULLETS", "uid": "f17107f0a25a11e7b7c67054d2175f18" }, { "children": [ "f17109bca25a11e7b7c67054d2175f18", "f1710aa2a25a11e7b7c67054d2175f18", "f1710b88a25a11e7b7c67054d2175f18", "f1710c78a25a11e7b7c67054d2175f18", "f1710d68a25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f17108e0a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Output line sequence", "Text": "Fix out of sequence output lines when output formats are longer than ten lines." }, "format": "BULLETS", "uid": "f17109bca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Node indenting", "Text": "Fix problems with unique IDs and internal links when indenting and unindenting nodes." }, "format": "BULLETS", "uid": "f1710aa2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Widget focus problems", "Text": "Avoid widget focus problems when editing data on conditional types." }, "format": "BULLETS", "uid": "f1710b88a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Format cursor position", "Text": "Maintain the output format cursor position when changing fields in the configure dialog." }, "format": "BULLETS", "uid": "f1710c78a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "XML import", "Text": "Fix importing of generic XML documents that have nodes with no data." }, "format": "BULLETS", "uid": "f1710d68a25a11e7b7c67054d2175f18" }, { "children": [ "f1710f48a25a11e7b7c67054d2175f18", "f17118a8a25a11e7b7c67054d2175f18" ], "data": { "Name": "May 2, 2013 - Release 1.9.1 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1710e58a25a11e7b7c67054d2175f18" }, { "children": [ "f171102ea25a11e7b7c67054d2175f18", "f171111ea25a11e7b7c67054d2175f18", "f171120ea25a11e7b7c67054d2175f18", "f17112fea25a11e7b7c67054d2175f18", "f17113eea25a11e7b7c67054d2175f18", "f17114dea25a11e7b7c67054d2175f18", "f17115d8a25a11e7b7c67054d2175f18", "f17116c8a25a11e7b7c67054d2175f18", "f17117b8a25a11e7b7c67054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "f1710f48a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Compression and encryption", "Text": "Added TreeLine file compression and file encryption, controlled from a File > Properties dialog box." }, "format": "BULLETS", "uid": "f171102ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Restore tree states", "Text": "Tree node open/close states are restored for recent files." }, "format": "BULLETS", "uid": "f171111ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Derived data types", "Text": "Added derived data types that keep the field list of their generic type." }, "format": "BULLETS", "uid": "f171120ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Conditional type setting", "Text": "Added conditional type setting that changes icons or output format based on field contents." }, "format": "BULLETS", "uid": "f17112fea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Other field references", "Text": "Other field references (file info, ancestors, children) can be used in node output formats and in print headers & footers." }, "format": "BULLETS", "uid": "f17113eea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "HTML file export", "Text": "Added an HTML file export to a single file with a navigation pane on the side." }, "format": "BULLETS", "uid": "f17114dea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Embedded blank lines", "Text": "Allow embedded blank lines in non-HTML node output formats." }, "format": "BULLETS", "uid": "f17115d8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Separator config option", "Text": "Added an output separator config option for combination fields and child references." }, "format": "BULLETS", "uid": "f17116c8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "First day of week option", "Text": "Add an option to set the first day of the week for calendar widgets." }, "format": "BULLETS", "uid": "f17117b8a25a11e7b7c67054d2175f18" }, { "children": [ "f1711998a25a11e7b7c67054d2175f18", "f1711a88a25a11e7b7c67054d2175f18", "f1711b6ea25a11e7b7c67054d2175f18", "f1711c54a25a11e7b7c67054d2175f18", "f1711d44a25a11e7b7c67054d2175f18", "f1711e2aa25a11e7b7c67054d2175f18" ], "data": { "Name": "Bug Fixes" }, "format": "BULLET_HEADING", "uid": "f17118a8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Drag multiple nodes", "Text": "Fixed problems with pasting or dragging multiple nodes." }, "format": "BULLETS", "uid": "f1711998a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Remove fields from multi-line output formats", "Text": "Made removing fields from multi-line output formats work properly." }, "format": "BULLETS", "uid": "f1711a88a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Prevent duplicate unique IDs", "Text": "Prevent duplicate unique IDs from being created after undoing the deletion of a branch." }, "format": "BULLETS", "uid": "f1711b6ea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Fixed non-text nodes sorting", "Text": "Fixed node sorting of non-text nodes (numbers, dates, times, etc.)" }, "format": "BULLETS", "uid": "f1711c54a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Calendar widgets", "Text": "Avoid placing calendar widgets partially off screen if near the bottom." }, "format": "BULLETS", "uid": "f1711d44a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Automatic cell height", "Text": "Limit the automatic height increases for text edit cells to avoid confusing double scroll bars." }, "format": "BULLETS", "uid": "f1711e2aa25a11e7b7c67054d2175f18" }, { "children": [ "f171200aa25a11e7b7c67054d2175f18" ], "data": { "Name": "February 6, 2013 - Release 1.9.0 (unstable development snapshot)" }, "format": "HEADINGS", "uid": "f1711f24a25a11e7b7c67054d2175f18" }, { "children": [ "f17120e6a25a11e7b7c67054d2175f18", "f17121d6a25a11e7b7c67054d2175f18", "f17122c6a25a11e7b7c67054d2175f18", "f17123aca25a11e7b7c67054d2175f18", "f171249ca25a11e7b7c67054d2175f18", "f171258ca25a11e7b7c67054d2175f18", "f1712690a25a11e7b7c67054d2175f18", "f1712776a25a11e7b7c67054d2175f18", "f1712866a25a11e7b7c67054d2175f18", "f1712960a25a11e7b7c67054d2175f18", "f1712a46a25a11e7b7c67054d2175f18", "f1712b36a25a11e7b7c67054d2175f18", "f1712c1ca25a11e7b7c67054d2175f18", "f1712d02a25a11e7b7c67054d2175f18", "f1712df2a25a11e7b7c67054d2175f18", "f1712ed8a25a11e7b7c67054d2175f18", "f1712fbea25a11e7b7c67054d2175f18", "f1713194a25a11e7b7c67054d2175f18", "f1713284a25a11e7b7c67054d2175f18", "f171336aa25a11e7b7c67054d2175f18" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f171200aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Full Python 3 rewrite", "Text": "TreeLine has been fully rewritten using Python 3." }, "format": "BULLETS", "uid": "f17120e6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Direct model-view and ElementTree", "Text": "Improved performance due to direct use of model-view classes for views and ElementTree for input/output." }, "format": "BULLETS", "uid": "f17121d6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Table based data editor pane", "Text": "A table based data editor pane (much faster)." }, "format": "BULLETS", "uid": "f17122c6a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "WYSIWYG data editor view.", "Text": "WYSIWYG formatting in the data editor view." }, "format": "BULLETS", "uid": "f17123aca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Real-time window updates ", "Text": "Real-time updates of the same file shown in multiple windows." }, "format": "BULLETS", "uid": "f171249ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Improved printing", "Text": "Improved printing and print preview performance." }, "format": "BULLETS", "uid": "f171258ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saves print options", "Text": "Saves print options with the TreeLine file." }, "format": "BULLETS", "uid": "f1712690a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Built-in PDF", "Text": "Built-in print to PDF function." }, "format": "BULLETS", "uid": "f1712776a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Searching options.", "Text": "More searching options." }, "format": "BULLETS", "uid": "f1712866a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Filtering command", "Text": "A filtering command shows matches in a simple list." }, "format": "BULLETS", "uid": "f1712960a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Saved sorting parameters", "Text": "Sorting parameters can be saved with each data type." }, "format": "BULLETS", "uid": "f1712a46a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Basic text field type", "Text": "The basic text field type allows formatting, preserves line breaks and allows HTML restricted characters." }, "format": "BULLETS", "uid": "f1712b36a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Calendar widget", "Text": "A calendar widget can be used for editing date fields." }, "format": "BULLETS", "uid": "f1712c1ca25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Easy internal links", "Text": "Internal link fields and inline internal links are easier to use." }, "format": "BULLETS", "uid": "f1712d02a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Unified external links", "Text": "An external link type supports http, https, file and mailto protocols." }, "format": "BULLETS", "uid": "f1712df2a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Support relative paths", "Text": "Relative paths are supported for external links and pictures." }, "format": "BULLETS", "uid": "f1712ed8a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Regular expression field type", "Text": "A regular expression field type can match patterns (phone numbers, email addresses, etc.)" }, "format": "BULLETS", "uid": "f1712fbea25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Node IDs automatically generated", "Text": "Unique node IDs are automatically generated and updated." }, "format": "BULLETS", "uid": "f1713194a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "New windows installer", "Text": "A new windows installer allows a single-user, non-administrator install." }, "format": "BULLETS", "uid": "f1713284a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Portable installs", "Text": "Includes better support for portable installs." }, "format": "BULLETS", "uid": "f171336aa25a11e7b7c67054d2175f18" }, { "children": [ "f171354aa25a11e7b7c67054d2175f18", "f1713644a25a11e7b7c67054d2175f18", "f171372aa25a11e7b7c67054d2175f18" ], "data": { "Name": "\u041a\u043e\u043d\u0442\u0430\u043a\u0442\u044b", "Name_src": "Contacts" }, "format": "HEADINGS", "uid": "f1713464a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u0421\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438", "Name_src": "Mailing list", "Text": "\u0421\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u043e\u0431\u0441\u0443\u0436\u0434\u0430\u0442\u044c \u0432\u0441\u0435 \u0438 \u0432\u0441\u044f \u043e TreeLine. \u042d\u0442\u043e \u043c\u0435\u0441\u0442\u043e \u0434\u043b\u044f \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 (\u043e\u0442 \u0434\u043e\u0440\u043e\u0436\u043d\u044b\u0445 \u043a\u0430\u0440\u0442 \u0434\u043e \u043f\u0440\u0435\u0434\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043f\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u044f\u043c \u0438 \u0431\u0435\u0442\u0430-\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f), \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0438\u0439 \u043e \u0432\u044b\u043f\u0443\u0441\u043a\u0430\u0445, \u043e\u0442\u0447\u0435\u0442\u043e\u0432 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445 \u0438 \u043e\u0431\u0449\u0438\u0445 \u043e\u0431\u0441\u0443\u0436\u0434\u0435\u043d\u0438\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439 (\u043e\u0442 \u043d\u043e\u0432\u044b\u0445 \u043e\u0431\u043b\u0430\u0441\u0442\u0435\u0439 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0434\u043e \u0441\u043e\u0432\u0435\u0442\u043e\u0432, \u043f\u0440\u0438\u0435\u043c\u043e\u0432 \u0438 \u043e\u0431\u0440\u0430\u0437\u0446\u043e\u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438). \n
    \n
    \n\u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u043f\u0438\u0441\u0430\u0442\u044c\u0441\u044f, \u043f\u0435\u0440\u0435\u0439\u0434\u0438\u0442\u0435 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 lists.sourceforge.net/lists/listinfo/treeline-users", "Text_src": "There is a low-volume mailing list for users to discuss anything and everything about TreeLine. This is the place for development discussions (from roadmaps to feature suggestions to beta testing), release announcements, bug reports, and general user discussions (from new uses to tips & tricks to configuration samples).
    \n
    \nTo subscribe, go to lists.sourceforge.net/lists/listinfo/treeline-users
    \n" }, "format": "HEAD_PARA", "uid": "f171354aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Email", "Name_src": "Email", "Text": "\u0415\u0441\u043b\u0438 \u0432\u044b \u043d\u0435 \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u043e\u0434\u043f\u0438\u0441\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438, \u0441\u043e \u043c\u043d\u043e\u0439 \u043c\u043e\u0436\u043d\u043e \u0441\u0432\u044f\u0437\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u0435: doug101 \u041a\u041e\u041c\u041c\u0415\u0420\u0427\u0415\u0421\u041a\u041e\u0415 AT bellz \u0422\u041e\u0427\u041a\u0410 org", "Text_src": "If you do not wish to subscribe to the mailing list, I can be contacted by email at: doug101 AT bellz DOT org " }, "format": "HEAD_PARA", "uid": "f1713644a25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f", "Name_src": "Updates", "Text": "\u042f \u043f\u0440\u0438\u0437\u043d\u0430\u0442\u0435\u043b\u0435\u043d \u0437\u0430 \u043b\u044e\u0431\u044b\u0435 \u043e\u0442\u0437\u044b\u0432\u044b, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435 \u0437\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043e \u043b\u044e\u0431\u044b\u0445 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043d\u044b\u0445 \u0432\u0430\u043c\u0438 \u043e\u0448\u0438\u0431\u043a\u0430\u0445. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0435\u0440\u0438\u043e\u0434\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0439 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 \u043f\u043e \u0430\u0434\u0440\u0435\u0441\u0443: treeline.bellz.org.", "Text_src": "I welcome any feedback, including reports of any bugs you find. Also, you can periodically check back to treeline.bellz.org for any updates." }, "format": "HEAD_PARA", "uid": "f171372aa25a11e7b7c67054d2175f18" }, { "children": [], "data": { "Name": "Network drive issues", "Text": "Work around bugs when using files located on some types of Windows network drives." }, "format": "BULLETS", "uid": "f2a0c0a1dc8d11ea8921ac675dac20af" }, { "children": [], "data": { "Name": "Error handling", "Text": "Error handling has been improved. For most errors, a dialog box is shown with debugging information that can be copied into an email." }, "format": "BULLETS", "uid": "f5983b38bb0411e795e13417ebd53aeb" }, { "children": [ "42fb4166305a11e99fd7a44cc8e97404", "014e1392305b11e9ab99a44cc8e97404", "46f3d0a4305e11e9892fa44cc8e97404", "f7bbd90a305111e98209a44cc8e97404", "221ca8f0305911e99f3fa44cc8e97404", "2c9ba0c832ed11e9bf7f7054d2175f18", "2d4430dc305711e9a33aa44cc8e97404", "1b73aaf4305811e98bb7a44cc8e97404" ], "data": { "Name": "New Features" }, "format": "BULLET_HEADING", "uid": "f7bbd909305111e9be43a44cc8e97404" }, { "children": [], "data": { "Name": "Regenerate references command", "Text": "A new Regenerate References command was added to the Data menu. It forces updates to all conditional types and math fields. It should only be necessary for comparisons to current dates/times or for externally modified data." }, "format": "BULLETS", "uid": "f7bbd90a305111e98209a44cc8e97404" }, { "children": [], "data": { "Name": "XML export", "Text": "Fixed problems with generic XML export from multiple root nodes." }, "format": "BULLETS", "uid": "f817e5b6334a11e89349d66a6ab671cb" }, { "children": [], "data": { "Name": "Spanish translation", "Text": "Added a Spanish GUI translation (thanks to Diego)." }, "format": "BULLETS", "uid": "f966db0cc23f11e8b80fd66a6ab671cb" }, { "children": [], "data": { "Name": "Printing empty branches", "Text": "Fix an error caused by attempting to print an empty branch." }, "format": "BULLETS", "uid": "fcc1b718e5df11e9a7f9a44cc8e97404" }, { "children": [], "data": { "Name": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u041f\u0435\u0447\u0430\u0442\u0438", "Name_src": "Print Setup", "Text": "\u0414\u0438\u0430\u043b\u043e\u0433\u043e\u0432\u043e\u0435 \u043e\u043a\u043d\u043e \u0434\u043b\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u0435\u0447\u0430\u0442\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0447\u0435\u0442\u044b\u0440\u0435 \u0432\u043a\u043b\u0430\u0434\u043a\u0438. \u041f\u0435\u0440\u0432\u0430\u044f, \u00ab\u041e\u0431\u0449\u0438\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u00bb, \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0432 \u0441\u0435\u0431\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u044e\u0449\u0438\u0435 \u043a\u0430\u043a\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0434\u0435\u0440\u0435\u0432\u0430 \u043f\u0435\u0447\u0430\u0442\u0430\u0442\u044c, \u0432\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043b\u0438 \u0441\u0442\u0440\u043e\u043a\u0438 \u0432 \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u0435 \u0443\u0437\u043b\u044b \u0438 \u0440\u0430\u0437\u0440\u0435\u0448\u0430\u0442\u044c \u043b\u0438 \u0440\u0430\u0437\u0440\u044b\u0432\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u043c\u0435\u0436\u0434\u0443 \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u043c \u0438 \u0435\u0433\u043e \u043f\u0435\u0440\u0432\u044b\u043c \u0434\u043e\u0447\u0435\u0440\u043d\u0438\u043c \u0443\u0437\u043b\u0430\u043c\u0438. \u0412 \u043d\u0435\u043c \u0442\u0430\u043a\u0436\u0435 \u0438\u043c\u0435\u0435\u0442\u0441\u044f \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u0438 \u043f\u0435\u0447\u0430\u0442\u0438, \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043b\u0435\u043d\u0438\u044f \u0431\u043e\u043b\u0435\u0435 \u0442\u043e\u0447\u043d\u043e\u0439 \u043d\u0443\u043c\u0435\u0440\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0438 \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u043f\u0435\u0447\u0430\u0442\u0438. \u0412\u0442\u043e\u0440\u0430\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 \u00ab\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b\u00bb \u0432\u043a\u043b\u044e\u0447\u0430\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0431\u0443\u043c\u0430\u0433\u0438, \u043e\u0440\u0438\u0435\u043d\u0442\u0430\u0446\u0438\u0438, \u043f\u043e\u043b\u0435\u0439 \u0438 \u0441\u0442\u043e\u043b\u0431\u0446\u043e\u0432 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b. \u0422\u0440\u0435\u0442\u044c\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430 [\u00ab\u0412\u044b\u0431\u043e\u0440 \u0448\u0440\u0438\u0444\u0442\u0430\u00bb] \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u0431\u0440\u0430\u0442\u044c \u0448\u0440\u0438\u0444\u0442 \u0434\u043b\u044f \u043f\u0435\u0447\u0430\u0442\u0438. \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0432\u043a\u043b\u0430\u0434\u043a\u0430, \u00ab\u0412\u0435\u0440\u0445\u043d\u0438\u0439/\u043d\u0438\u0436\u043d\u0438\u0439 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b\u00bb, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u043c\u0435\u0442\u0430\u043f\u043e\u043b\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u0434\u0430\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u0430 \u0434\u043b\u044f \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f \u0438\u0445 \u0432 \u0432\u0435\u0440\u0445\u043d\u0438\u0435 \u0438 \u043d\u0438\u0436\u043d\u0438\u0435 \u043a\u043e\u043b\u043e\u043d\u0442\u0438\u0442\u0443\u043b\u044b.", "Text_src": "The dialog for print setup contains four tabs. The first, General Options, includes settings for what part of the tree to print, whether to include lines to child nodes and whether to allow page breaks between a parent an its first child node. It also has place to set the printer queue, to make pagination and print previews more accurate. The second tab, Page Setup, includes paper size, orientation, margins and columns. The third tab selects the font for printing. The last tab, Header/Footer, defines text and file data meta-fields for inclusion in headers and footers." }, "format": "HEAD_PARA", "uid": "fd0fe3dd69dc11ebab13001fd026534b" }, { "children": [ "6a6067d4482011e989f27054d2175f18", "b398d8ee482211e989f27054d2175f18", "ff3f7da6481e11e989f27054d2175f18" ], "data": { "Name": "Updates" }, "format": "BULLET_HEADING", "uid": "ff3f7c98481e11e989f27054d2175f18" }, { "children": [], "data": { "Name": "Translations", "Text": "Updated German and Spanish GUI translations (thanks to Maria Seliger and Diego)." }, "format": "BULLETS", "uid": "ff3f7da6481e11e989f27054d2175f18" } ], "properties": { "tlversion": "3.2.1", "topnodes": [ "f16f7d90a25a11e7b7c67054d2175f18" ] } }TreeLine-3.2.1/docs/000077500000000000000000000000001506556630100141635ustar00rootroot00000000000000TreeLine-3.2.1/docs/CNAME000066400000000000000000000000221506556630100147230ustar00rootroot00000000000000treeline.bellz.orgTreeLine-3.2.1/docs/default.css000066400000000000000000000026641506556630100163310ustar00rootroot00000000000000/* bellz.org style sheet */ body { background: #033; color: white; } a { color: #0f9; text-decoration: none; } a:hover { text-decoration: underline; } hr { height: 4px; } h1 { text-align: center; border-top: thick double #ccc; padding: .3em; margin: 1em 0 0; clear: both; } h2 { border-top: thin solid #ccc; padding: .3em 0 0; margin: 1em 0 0; } ul { margin-left: 0; } li { list-style-type: square; padding: .2em 0; margin-left: 2em; } img { border: 0; } .interior { margin: 0 auto; width: 90%; } .title { margin: 0; padding: 4px 0; float: left; } .title h1 { font-size: 4em; margin: 0; padding: 0; } .toplinks { float: right; text-align: right; } .toplinks p { margin: 0; padding: 0; } .navigation { clear: both; line-height: 3em; margin: 0; padding: 0; } .navigation a { background: #366; margin-right: 3px; padding: .4em .4em; } .navigation a:hover { background: #099; text-decoration: none; } .current-nav { background: #366; margin-right: 3px; padding: .4em .4em 1em; } .content { background: #366; margin: 0 0 2em; padding: .5em 1.5em; zoom: 1; /* fixes IE layout bug */ /* height: 1%; /* fixes IE layout bug */ } .centered { text-align: center; } .smallimage { float: left; margin: 0 1em; } .clearer { clear: both; } TreeLine-3.2.1/docs/download.html000066400000000000000000000107111506556630100166600ustar00rootroot00000000000000 TreeLine - Downloads
    TreeLine

    TreeLine Downloads

    Linux

    On a Linux system that has the libraries noted on the requirements page, all that is needed is the source code (with an installer script).

    Alternately, TreeLine packages are available from the repositories in many popular distrobutions.

    Also, please read about the installation and use of TreeLine.

    Windows

    Multiple windows installers are available.

    The source code for the libraries used to build the Windows binaries is available upon request.

    Also, please read about the installation and use of TreeLine.

    Older Versions

    Previous versions of TreeLine are available from SourceForge.

    TreeLine-3.2.1/docs/favicon.png000066400000000000000000000045251506556630100163240ustar00rootroot00000000000000PNG  IHDR00WsBIT|d pHYstEXtSoftwarewww.inkscape.org<IDATh{p?G6ݼ7!H ѦSσxӻQA^%S94p,'N擦 jހ&c:}Exg۟JŎ{`n2 O2~6ɚtn5kxMzkx>m۬cҚ`<1Oh'VzVMs:tr A^zNz;;|;w;3gYD'xGuJUqY2Coկ,2S-ٻ;GϘtt[/y sMMI (YΝ y wY։!5 *z?.}`JD⸴ff\76ה?p$m'd#!FV#"fhs̳|*{`(,bHFf@H;UUd +p|Sjʲ19PNEm}n!(mRw ĴHBl7|)LɺtmxW$ʹ~R1R:lYOɜ=Z9;Bu7$"?HAM.]"o n5c\ȥlO1>wNv:ΰ^9|.ҕ,u )Q硼bZ?1Hq[6?K7UQ Uq5Yj`poI @xì>|-Zz7L31Pe\e3p(*N'sƟ7W c"F b2U+%?qC?cEj)B1:^PVɔ1ī/dЋCgaVT /$C$Ua;M1BO??ENZNՃN$?oإ^m;RWםKȡ?A]9'RW׳@pAu G[Mޣ$s#TGut9֯ᥤJajBY1x>61mhCr0we7RL_3oCb=jf+m ovVć39-rqs[nxTq=ĚhP%Y۶5]g lw/3F4F';ՠR=ބC_M鬿'^s7VK#B1ىmR(KǑsO/cggv p, kG=QQjʗF$%8@`f_ΣUP&nk홚G/<`:: s5d i}F/4(l;wK&$mR\.$[5`DdqT٨H!,툏OvM*}>eYg|qNWKXU0抏[+Vط2"b/A_s&SF/Z?`9RrI62T/,pZIk0tp]fk 3PLA;5~לhT>ؿx2sdpG'젷Pw=hшm˗ˌnѥ|ԯqBc HVZo.bYgo@q]io-ڏK,q]$O tW<89 Lc']O6R:)Roj64 849GT5M:MIENDB`TreeLine-3.2.1/docs/feature.html000066400000000000000000000160011506556630100165020ustar00rootroot00000000000000 TreeLine - Features
    TreeLine

    TreeLine Features

      General
    • Stores almost any type of information, including plain text, rich text, HTML, numbers, dates, times, booleans, URLs, etc.
    • The tree structure helps keep things organized.
    • Each node can have several fields that form a mini-database.
    • Several node types, with different sets of fields, can be included in one file.
    • The node format, including fields, output lines, formatting and tree-view icon, can be defined for each node type.
      Views
    • The left-hand view shows an indented, expandable list of titles
    • The right-hand view can show one of three views - for showing output, editing node data and editing node titles.
    • The right-hand view is normally split to show data from the parent node and its children.
    • If multiple nodes are selected, the right-hand view shows all of their data.
    • The output view can be set to show indented output from all descendant nodes.
    • An upper breadcrumb view shows titles of the selected node's ancestors; the titles can be clicked to select them in the tree.
      Navigation
    • Find commands can search node data for text matches or for more specific rules.
    • Filtering commands show only matching nodes in a flat left-hand view.
    • Previous and next selection commands toggle selections to quickly move between parts of the tree.
      Formatting
    • The dialog for data type configuration has several tabs to easily set all type, field and output parameters.
    • Each tree node can be set to a type format independently.
    • Formatting information can be copied from another TreeLine file.
      File Handling
    • Undo and redo commands are available for all modifying operations.
    • TreeLine files use a JSON format, with options for automatically compressing or encrypting the files.
    • Document templates for new files are preformatted to cover basic needs.
    • The formatted output can be printed with parent/child lines, headers and footers.
      File Import and Export
    • The data can be exported to single or multiple HTML files with optional navigation panes.
    • A live tree HTML export creates an interactive view with expandable nodes and a descendant output pane.
    • Plain text, tab-indented text and delimited table files can be imported and exported.
    • Files from older versions of TreeLine (2.x and 1.x) can be imported and exported.
    • Mozilla and XBEL format bookmark files can be imported and exported.
    • Generic XML files can be imported and exported, allowing TreeLine to function as a crude XML editor.
    • ODF text documents can be imported and exported as outlines.
      Linking
    • Internal link fields select a linked node when clicked.
    • External link fields can be used to open URLs in web browsers.
    • Both internal and external links can be embedded into text fields.
    • Nodes that are duplicated by cloning show up as separate clickable paths in the upper breadcrumb view.
      Data Manipulation
    • Nodes can be sorted by title or by predefined key fields.
    • Math fields can be defined that automatically calculate their contents based on numerical values in other nodes.
    • Numbering fields can be defined and automatically updated.
    • A node's icon and output format can be changed conditionally based on its data.
    • Cloned nodes (the same nodes with multiple parents/locations) can be created using special paste commands or by automatically matching identical nodes.
    • Text data can be spell checked (requires an external program - see the System Requirements section).
    • Data can be automatically re-arranged using categories from data fields.
      Customization
    • There are many options for customizing both general and file-based attributes.
    • There are editors for keyboard shortcuts and toolbar commands.
    • Fonts used in the GUI, editors and output views can be customized.
    • The user interface is available in simplified Chinese, English, German, Russian and Spanish. Translations into other languages are TBD.
    TreeLine-3.2.1/docs/index.html000066400000000000000000005303611506556630100161700ustar00rootroot00000000000000 TreeLine - News
    TreeLine

    What is TreeLine?

    Do you have lots of sticky notes lying around with various useful information jotted down? Or many lists of books, movies, website logins, personal contacts, or things to do? Can you find them when you need them? Well, I often couldn't. So here's my answer.

    Some would call TreeLine an Outliner, others would call it a PIM. Basically, it just stores almost any kind of information. A tree structure makes it easy to keep things organized. And each node in the tree can contain several fields, forming a mini-database. The output format for each node can be defined, and the output can be shown on the screen, printed, or exported to html.

    A source code repository is available at GitHub.

    There is a low-volume email list for users to discuss TreeLine. To subscribe, go to this page.

    News

    September 27, 2025 - Release 3.2.1 (stable release)

      Updates:
    • Added an easily selectable light-colored theme option.
      Bug Fixes:
    • Fixed errors that occurred when dragging and dropping nodes and files.
    • An error setting some page sizes for printing was fixed.
    • Fixed the appearance of the print preview when a dark theme is being used.
    • Fixed the appearance of the time edit widget when used with a dark theme.
    • A problem with the option to minimize to the system tray was fixed.

    August 30, 2025 - Release 3.2.0 (stable release)

      New Features:
    • Made extensive updates to port TreeLine to the Qt6 and PyQt6 libraries.
    • Added a word count function for math field types.
      Updates:
    • Removed deprecated string escapes used when formatting numbers.
      Bug Fixes:
    • Fixed errors closing a window if the same file is open in another window.
    • Fixed a problem with the filter view when the tree icon is set to none.
    • Improved the handling of multi-line text in generic XML import.

    June 3, 2023 - Release 3.1.6 (stable release)

      Updates:
    • Detect external file modifications by checking the file's last modified time just prior to saving.
    • Preserve the choices in the field format when switching between Choice and Combination field types.
      Bug Fixes:
    • Fix a bug that prevented child type limits from being set back to all types.
    • Preserve the modified status of the config dialog when switching between windows displaying different files.
    • Fix problems occurring when the escape key is used to close various non-modal dialogs.
    • Avoid a traceback error message when attempting to import a CSV file with a bad header row.
    • Fix a bug using child count fields in live HTML exports.

    September 10, 2022 - Release 3.1.5 (stable release)

      New Features:
    • Add a command for strike-through font formatting.
      Updates:
    • For better visibility, increase the width of tree structure lines in printed and PDF output files.
    • Update the libraries used to build the Windows binaries to Python 3.10 and Qt/PyQt 5.15. Note that this eliminates support for Windows 7.
    • Add a Russian translation of the GUI and the help files (thanks to Andrew Trofimov).
    • Update the German GUI translation (thanks to Karsten).
      Bug Fixes:
    • Fix a bug preventing a second-try password entry from opening an encrypted file.
    • Add fallbacks to UTF-8 encoding if the OS encoding fails on import and export.
    • Avoid a crash when bad field name modifiers are in a math field equation.

    November 28, 2020 - Release 3.1.4 (stable release)

      Bug Fixes:
    • Fix an incompatibility with the new Python 3.9 version under Linux or running from source.
    • Avoid an error message when a window is closed with the focus on a dialog box.
    • Fix a problem recalculating root references in field equations.

    August 16, 2020 - Release 3.1.3 (stable release)

      New Features:
    • Add a more flexible tool for customizing GUI colors.
    • Add an Insert Date command that adds a timestamp to text field edit boxes.
    • Evaluate math expressions contained in fields that are referenced by math field equations.
    • Add support for German outline numbering using double letters in some levels (thanks to Teresa M).
      Updates:
    • Update math field equation restrictions to work with Python 3.8.
    • References to a macOS port on MacPorts were added to the System Requirements and Installation documentation.
    • Update the libraries used to build the Windows binaries to Python 3.8 and Qt/PyQt 5.14.
      Bug Fixes:
    • Make the Add Child command available after filtering has ended.
    • Avoid an application error when a Find and Replace command causes fields to contain invalid data.
    • Perform a more complete recalculation of math fields after certain operations.
    • Fix problems opening files that contain circular reference errors in math fields.
    • Avoid problems with empty parameters in the font dialogs.
    • Fix a bug in Data Edit views when no fields are visible due to hidden numbering or math fields.
    • Properly update multiple windows after drag and drop tree changes.
    • Fix issues with restoring window geometry with multiple monitors and changing configurations.
    • Work around bugs when using files located on some types of Windows network drives.
    • Fix problems detecting existing TreeLine sessions when opening files (mostly in Linux).

    October 6, 2019 - Release 3.1.2 (stable release)

      New Features:
    • Add a simplified Chinese GUI translation (thanks to Qu Ray for translating).
    • Add a general option to extend the height of data editors with long text content. The default setting (limit the height to the window size) is unchanged. The new option uses the view scroll bars to access the full text length.
      Updates:
    • Restore the cursor and scroll positions of data editors when the editors are re-created after focus changes.
    • Add an asterisk after the file name in the title bar if a file has been modified.
    • Change lettered outline numbering sequences to match standards. The sequences change from ...Y, Z, AA, AB, AC... to ...Y, Z, AA, BB, CC...
      Bug Fixes:
    • Fix a bug that truncated plain text exports after the first line.
    • Enable the title list view's select in tree context menu to be used on new child nodes.
    • Modify dark mode colors to make tool tips visible.
    • Fix error due to character encoding when importing files from Treepad.
    • Fix an error caused by attempting to print an empty branch.

    March 17, 2019 - Release 3.1.1 (stable release)

      Updates:
    • Added many Show Configuration Structure data fields to show detailed settings for type formats and field formats.
    • Added support for finding and replacing empty data fields using the search and replace command.
    • Updated German and Spanish GUI translations (thanks to Maria Seliger and Diego).
      Bug Fixes:
    • Fix printing problems when using the dark theme.
    • Fix incorrect numbering updates in some situations with mixed node types.
    • Fix problems defining a math field equation on a recently copied data type.
    • Eliminate a problem defining math field equations that include child count references.
    • Fix a minor bug affecting default directories for save-as and export commands when there is not already a file name set.

    February 20, 2019 - Release 3.1.0 (beta release)

      Notes:
    • This is a beta release of TreeLine. Some new features have not been extensively tested, but major bugs are unlikely. Testing and bug reports are appreciated, but those with very critical work should consider using the stable release (TreeLine 3.0.x).
    • GUI translations are available in German and Spanish, but they still require minor updates to cover recent changes. Volunteers are also needed to update or create translations in additional languages.
      New Features:
    • A Select in Tree command was added to the Title List's right-click context menu. It selects the node corresponding to the current line in the Title List editor. This makes it easier to edit or add children to an item.
    • A minimize to system tray option was added to General Options (under Features Available). If enabled, it adds a TreeLine system tray icon to toggle application display and hides the taskbar entry when TreeLine is minimized.
    • An optional dark color theme was added to General Options (under Appearances).
    • A new Regenerate References command was added to the Data menu. It forces updates to all conditional types and math fields. It should only be necessary for comparisons to current dates/times or for externally modified data.
    • Added support for current date and time references to math fields. Special field names ({*Now_Date*}, {*Now_Time*} and {*Now_Date_Time*}) must be manually typed in equations.
    • A new Show Configuration Structure command was added to the Data menu. This opens a read-only visualization of complex type structures as another TreeLine file.
    • An indent (pretty print) output option was added to General Options (under Features Available). This makes saved TreeLine JSON files easier for humans to read at the expense of somewhat larger file sizes.
    • The Evaluate HTML tags control was enabled for date, time, boolean and math fields. This allows HTML tags to be evaluated or ignored in more field types.
      Updates:
    • The top root node is now selected at file open if there is not a recent selection state to restore. Previously these files opened with no selection, which could cause confusion.
    • Non-editable math fields in the Data Edit view show as gray when the mouse hovers over them.
    • Some unnecessary libraries were eliminated from the Windows installer to reduce download sizes and installed space requirements.
      Bug Fixes:
    • Fixed the truncation of node titles that are generated from the first line of HTML Text fields.
    • Some redundant newline characters were removed from text storage in TreeLine files.

    November 17, 2018 - Release 3.0.3 (stable release)

      Bug Fixes:
    • Fixed an error when adding child count fields to the output format.
    • Problems with writing config files in Windows portable installations were fixed.
    • Improved error handling after failing to read or write config files.
    • In the Windows installer, improve the deletion of files from older versions and avoid problems if installing into a directory shared with other applications.

    October 20, 2018 - Release 3.0.2 (stable release)

      Updates:
    • Upgraded the Windows binary from Python 3.6 to Python 3.7.
      Bug Fixes:
    • Fixed nonfunctional printing commands under Windows by building the Windows binary using PyInstaller rather than cx_Freeze.
    • Multiple issues with printing long nodes were fixed.
    • Fixed problems saving files when the blanks as zeros property was changed for math fields.

    September 29, 2018 - Release 3.0.1 (stable release)

      Updates:
    • Added a Spanish GUI translation (thanks to Diego).
    • Added a read-only text box to the Help > About dialog to allow copying of the version and library information.
      Bug Fixes:
    • Fixed a problem opening old TreeLine files that had format changes in File Info fields.
    • TreeLine files with invalid child references can now be opened. A warning message is given about the missing child nodes in the corrupt file.
    • The Sort command now properly sorts multiple root nodes when sorting the entire tree.
    • Now forces references to AM/PM in time field formats to be output regardless of system locale settings.
    • Data from fields that were removed from the configuration is now purged when a file is saved. This avoids missing matches in the Clone All Matched Nodes command.
    • Fixed various errors when applying advanced clone and category commands from the Data menu to complex node structures.
    • Fixed some problems with using the Undo command after complex operations.
    • Fix an error caused by attempting to use the Edit > Cut command when there is only one node.

    August 19, 2018 - Release 3.0.0 (new stable release)

      Notes:
    • This is the first stable release of a major TreeLine rewrite. It includes all of the new features shown below in the 2.1.x and 2.9.x development series.
    • TreeLine files now use a JSON format in place of the old XML format. This provides more flexibility for structuring new features like cloned nodes and multiple root nodes. A new file extension (".trln) helps to distinguish files with the new format. Import and export filters are provided for older TreeLine version 2.x and 1.x files. The older files can be opened using the standard "File > Open" command.
    • A GUI translations is available in German. All other translations are out of date and have not been included. Volunteers are needed to update translations in several languages.
      New Features:
    • The default font for the application can now be set in Tools > Customize Fonts. This is useful for enlarging fonts on some systems with high screen resolutions. Options still exist to individually specify tree view, output view and editor fonts.
      Updates:
    • The Windows binary is now built using updated libraries (Qt 5.11 and PyQt 5.11).

    June 30, 2018 - Release 2.9.2 (unstable development snapshot)

      Notes:
    • This is a development snapshot of TreeLine that should be considered a release candidate for an upcoming stable release. Many bugs have been fixed. User testing and bug reports are appreciated.
    • This is a major rewrite of TreeLine. Once it becomes fully stable, it will be released as TreeLine version 3.0.0.
    • A GUI translations is available in German. All other translations are out of date and have not been included. Volunteers are needed to update translations in several languages.
      Updates:
    • The German GUI translation was updated (thanks to Maria Seliger).
    • The expand/collapse status of nearby nodes is maintained while editing the node structure. This includes adding, deleting, moving and indenting nodes.
    • The expanded/collapsed and selected tree states are now saved even if changes were discarded in the previous session.
    • A click on a tree node to restore tree focus no longer starts editing the node title.
    • The enter key now selects a tree node after the first title letter(s) are typed to make it current (shown with a box around the title).
      Bug Fixes:
    • Several errors occurring when deleting or removing nodes have been fixed. These include problems when the mouse is pre-highlighting descendant nodes and when nodes to be deleted are selected in a separate window.
    • Fixed node title editing errors caused by moving the mouse to a data edit box with the title edit still active.
    • Fixed errors occurring when field types are changed after initial default values have been set.

    March 31, 2018 - Release 2.9.1 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of TreeLine. It has improved but could still contain bugs. Testing and bug reports are appreciated, but those with very critical work should consider using the stable release (TreeLine 2.0.x).
    • This is a major rewrite of TreeLine. Once it becomes more stable, it will be released as TreeLine version 3.0.0. The 2.1.x unstable series is being discontinued (no stable 2.2.0 release is planned).
    • The GUI and documentation translations are out of date and have not been included. Volunteers are needed to update translations in several languages.
      New Features:
    • A new HTML export uses Javascript and CSS to create a live tree view. Nodes in the tree can be expanded and collapsed, and a separate pane shows the output for all descendants of the selected node. One form of this export creates separate files that are linked to the existing TreeLine file. These files are intended for use on a web server (browser security usually prevents local access). Only the TreeLine file needs to be replaced to update the data (re-export is not required). The second form creates a single file (with embedded data) that can be accessed from a local web browser.
    • New forms of CSV table text imports and exports can work with multiple levels of child nodes, preserving the tree structure. The first column of the table includes a level number that is incremented for child relationships.
    • Added a custom time select dialog box for editing Time and TimeDate fields.
    • A new general option controls whether inaccessible files are removed from the recent file list at startup. The files are removed by default, but this can be changed to avoid losing listings of files stored on removable drives.
      Bug Fixes:
    • Fix errors shown when using copy commands after closing TreeLine windows.
    • Fixed problems with copy / paste and drag / drop on nodes with conditional type settings.
    • Avoid problems showing the tree view after closing a filter command that found no matches.
    • Fixed issues on Windows with pull-down combo boxes not working after repeatedly showing some dialogs (mostly find and filter dialogs).
    • Fixed problems with generic XML export from multiple root nodes.
    • Fixed problems with number field formatting when using a "," radix with exponents.
    • Avoid issues resolving relative paths between different Windows drive letters in external link fields.
    • Fixed problems with advanced ancestor field output references in some tree locations.
    • Properly update the right-hand views after using a new window command.
    • Avoid problems running data category-based commands on selections without any child nodes.
    • Fixed minor spacing issues for tables shown in output views and HTML exports.

    January 28, 2018 - Release 2.9.0 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of TreeLine. It could contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) is recommended for critical work.
    • This is a major rewrite of TreeLine. Once it becomes more stable, it will be released as TreeLine version 3.0.0. The 2.1.x unstable series is being discontinued (no stable 2.2.0 release is planned).
    • The GUI and documentation translations are out of date and have not been included. Volunteers are needed to update translations in several languages.
      New Features:
    • TreeLine files now uses a new JSON format in place of the old XML format. This provides more flexibility for structuring new features like cloned nodes and multiple root nodes. A new file extension (".trln) helps to distinguish these files.
    • Import and export filters are provided for older TreeLine version 2.x and 1.x files. The older files can be opened using the standard "File > Open" command.
    • Multiple top-level (root) nodes are now permitted. When no nodes are selected in the tree (by clicking on a blank area or Ctrl clicking to unselect), the right-hand view will show information about all of the top-level nodes.
    • A new breadcrumb view pane above the other panes shows a sequence of ancestor titles for a selected node. The ancestors can be clicked to select them. For cloned nodes, multiple lines provide links to each instance's ancestor sequence.
    • By default, the edit boxes in the data edit view now activate when the mouse hovers over them. This eliminates the need to click to activate them. This feature can be disabled in general options if desired.
    • When a file is opened in an existing window, the window is now reused (not just replaced) to eliminate flashing.
    • Cloned nodes now have a more native and efficient implementation. This allows the same nodes to have multiple parents. The new breadcrumb view shows a list of clones for the selected node that can be clicked to select the other instances.
    • New paste commands have been added for adding nodes before and after siblings. There are also multiple paste commands for adding clones of nodes.
    • Cloned nodes can be created automatically from all identical nodes by using the "Data > Clone All Matched Nodes" command.
    • The new "Data > Detach Clones" command converts cloned nodes in selected branches back into independent nodes.
    • A new "Swap Category Levels" command swaps child and grandchild nodes beneath a selected node. A child node with multiple nodes under it will become cloned under each one. Any existing grandchild clones will become individual nodes with multiple children.
    • Child node types that are available to be set can be limited. A new pull-down list of child type limits is in the "Type Config" tab of the configuration dialog if the advanced functions are shown.
    • The Date, Time and DateTime fields have new format strings that enable extra text to be added to the date output.
    • To improve efficiency, user visible node unique IDs that depend on the node's data have been removed.
    • Error handling has been improved. For most errors, a dialog box is shown with debugging information that can be copied into an email.
    • Added a desktop specification file to the Linux installer for desktop environment menu support.

    March 26, 2017 - Release 2.1.2 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of TreeLine. It may contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 2.0.x) should probably be used for critical work.
    • The GUI and documentation translations have not yet been updated.
      Bug Fixes:
    • Fix problems formatting DateTime fields in output views.
    • Fix dialog issues with clicking on targets when creating inline internal links.
    • Fix a regression that prevented using the tab key to cycle between data edit view items.
    • Avoid opening two windows when restoring an auto-saved backup file.

    March 12, 2017 - Release 2.1.1 (unstable development snapshot)

      Updates:
    • The Windows binary is now built using Python 3.6 and PyQt 5.8.
      Bug Fixes:
    • Fix a crash when changing the icon on the Type Config page of the Configure Data Types dialog box.
    • Fix inconsistent type selections on the Type List page of the Configure Data Types dialog box.
    • Fix issues with restoring the placement of the TreeLine window in some multiple monitor setups.

    February 20, 2017 - Release 2.1.0 (unstable development snapshot)

      New Features:
    • TreeLine has been ported from the Qt4 library to the Qt5 library. The system requirements have been updated to Python 3.4 or higher, PyQt 5.4 or higher and Qt 5.4 or higher.
    • Cloned nodes that can duplicate sections of the tree have been added. Editing their data or child structure in one location changes all locations. They are created by copying nodes and then using the "Edit->Paste Cloned Node" command to paste them elsewhere. The clone link can be removed by deleting the nodes or by cutting them and pasting them back using the regular paste command.
    • Added a new DateTime field that combines dates and times into a single field that is useful for timestamps. The editor format is a combination of the date and time formats from the general options, separated by a space.
    • Added an option to allow HTML tags in Choice, AutoChoice, Combination, AutoCombination and RegularExpression fields. The control is in the Field Config tab of the Configure Data Types dialog. This option is disabled by default. If enabled, special characters (angled brackets and quotation marks) will need to be escaped to show up in text.
    • Saved rules for Conditional Find and Conditional Filter commands are listed directly in the dialog boxes, making them easier to load and save.
    • Added comma-delimited (CSV) table import and export, similar to existing tab-delimited table import and export. The export only handles data from a single level of child nodes.
    • Added a quick, incremental search of node titles. By default, it's bound to ctrl+/. Then, matching titles are found as the search string is typed. The F3 and shift+F3 keys can be used to go to the next or previous matches, respectively.
    • Multiple fields can now be selected in the Output page of the Configuration dialog, so several fields can be added to the formats simultaneously.
    • A pull-down selector for printers has been added to the Print Setup dialog. This enables TreeLine to verify that the page size and margin settings are supported by the current printer.
      Updates:
    • The SpacedText Field now allows special HTML characters (angled brackets and quotation marks) without requiring them to be manually escaped.
      Bug Fixes:
    • The code that splits content into pages when printing has been improved. It now handles very long nodes better.
    • When formatted fields (dates, times, etc.) are used in node titles, editing the titles in the tree or in the Title List pane will now work if the edit and output formats are similar.

    October 3, 2015 - Release 2.0.2 (new stable release)

      Bug Fixes:
    • Fixed a major regression in 2.0.1 that broke data editors for most specialized field types (number, math, boolean, choice, etc.)
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    September 26, 2015 - Release 2.0.1 (new stable release)

      Updates:
    • Added methods to the plugin interface that allow general program options to be queried and changed.
    • Improve text table import error messages by including the line number where the problem is found.
      Bug Fixes:
    • Reduce the amount of work that a single undo command removes from editors in the data edit view.
    • Fixed a bug that prevented setting the unique ID reference field on a newly created data type.
    • Preserve hard newlines in text fields when converting TreeLine 1.4.x files to this version.
    • Fix problems preserving expand/collapse node states when indenting and unindenting nodes.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    May 17, 2015 - Release 2.0.0 (new stable release)

      Updates:
    • Modified the Treepad file import to use SpacedText fields to more closely match Treepad formatting.
    • An optional plugin was written that can export files to the Treepad text file format.
    • The TreeLine icon was replaced with a new one. Thanks to David Reimer for contributing the artwork.
    • The German and Portuguese GUI translations were updated.
    • Updated the long text sample file to include the SpacedText field type, and added a conditional equation to the math sample file.
    • Updated the Math Field section of the documentation.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    March 29, 2015 - Release 1.9.7 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It is nearly ready for a stable release, but it could still contain bugs. Testing and bug reports are appreciated.
    • The GUI and documentation translations are not yet complete.
      New Features:
    • Added comparison operators and conditional if statements to math field equations. The operators can be used with a new boolean result type, or as a part of numeric, date, time or text expressions.
    • Text operators were made available in math field equations, and the result type can be set to text. This allows math fields to combine text from other fields, replace substrings and change capitalization.
      Updates:
    • Added a "file saved" status bar message.
    • Added a German GUI translation.
    • Updated the Portuguese GUI translation.
      Bug Fixes:
    • Fixed a focus problem that made Combination and AutoCombination field editor pull-downs unusable.
    • Fixed a focus problem that made the pull-downs in choice and boolean field editors unusable on Linux.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    March 10, 2015 - Release 1.9.6 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It could still contain bugs. Testing and bug reports are appreciated.
    • The GUI and documentation translations are not yet complete.
      New Features:
    • Added a new OneLineText field type that restricts the text length to a single line.
    • Added an All Types option to the conditional find and filter commands. This allows multiple node types to be found or filtered at the same time. The fields from every type are available for use in conditions. The conditions give a false result for all node types that do not contain that field name.
    • Added support for date and time calculations using math fields. Math equation result types can be set to numeric, date or time output. Date fields can be subtracted to give the number of days elapsed, and numbers of days can be added to or subtracted from dates, resulting in new dates. Time fields can be subtracted to give the number of seconds elapsed, and numbers of seconds can be added to or subtracted from times, resulting in new times.
    • In math fields, added an equation reference level to reference fields in the root node. This provides a place for "constant" field values that can be referenced from any node but only need to be changed in one location.
    • Support was added for plugin extension modules. Most of the interface methods from TreeLine 1.4.x were duplicated to ease porting of old plugins. Of course, old plugins must be ported from Python 2.x to Python 3.x, and there are multi-window implementation differences. New interfaces allow the creation of new field types and the execution of any menu command. Sample plugins are available on the TreeLine download page.
    • Added text formatting and link commands for HTML fields that add tags to the HTML content.
    • An open in folder command was added to external link field editors to open the directory in a file manager.
    • Added the Select All command to global menus with a different default shortcut key (ctrl-L) to avoid conflicts with the add child shortcut.
      Updates:
    • Improved the focus handling for data edit view edit boxes. This eliminates the blue outline for boxes in inactive data edit views. It also makes tab-to-focus more predictable, including fully selecting single-line field types when they receive tab focus.
    • Data edit boxes are now automatically resized when editing is complete and the focus moves to another row.
    • Allow files to be drag & dropped on data edit boxes to create external links.
    • Small, non-modal dialogs, such as those for sorting, numbering, finding and filtering, have been set to stay on top, so they won't be obscured by TreeLine windows.
    • Made opening associated programs from external file links more consistent, especially in Linux.
    • The copy types from file command now supports encrypted and compressed files.
    • Added wait cursors to TreeLine operations that could be time consuming.
    • Improved the consistency of context menus and shortcut commands used in edit boxes.
    • Added a nearly complete Portuguese GUI translation.
    • Added support for sample TreeLine files to be provided in alternate languages.
    • Prepared the help file for translation into other languages,
      Bug Fixes:
    • Corrupted TreeLine files with the same unique ID assigned to multiple nodes no longer fail to open. The user is warned that unique IDs have been updated, which could break some internal links.
    • Fixed missing fields in the pull-down list in the conditional find and filter dialog boxes when a rule was re-used after a node type change.
    • Fixed problems with math fields that reference non-existing fields in parent or child nodes.
    • Made math fields update properly after node type changes.
    • Fixed inconsistent updates after renaming fields used with bulleted or tabled output.
    • Made node copy-paste and drag-and-drop work when the initial selection includes both parent and child nodes.
    • When importing a tabbed text file with multiple top-level nodes, create a single higher-level node to prevent failure.
    • Fixed the availability of the move up button in the customize toolbar dialog when the second command in the list is selected.
      Missing Features (not implemented yet):
    • Language translations for the GUI and documentation.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    December 31, 2014 - Release 1.9.5 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It is not yet complete and could contain bugs. Testing and bug reports are appreciated.
    • The GUI and documentation translations have not yet been done.
      New Features:
    • Added a math field type that is configured by defining an equation. The field value is automatically calculated based on references to numerical values in other nodes. See the "sample_math_fields" file for a usage example.
    • Added a Clear Formatting command that removes font changes and links from data editor text.
    • Made source code changes necessary to support user interface translations into other languages. The actual translation work remains to be done.
      Updates:
    • Add scroll bars to the pull-down editors for combination fields with many entries.
    • Reduce the truncation of external link URLs when generating default display names.
    • Use Unix-style newlines for saved TreeLine files to keep files consistent across platforms.
    • Update the CSS code in exported HTML with navigation panes to improve the appearance in some browsers.
    • Optimize some undo information to reduce the amount of data in memory.
    • Move sample files into a separate directory to avoid future translation conflicts.
    • Clarify a Linux installer error message when checking for the Python 3 version of PyQt.
    • Include MSVCR DLL files in the Windows installer.
      Bug Fixes:
    • Fix problems applying multiple configuration changes while the Configure Data Types dialog box remains open.
    • In the Title List editor, splitting a title into two lines now creates a new node without losing the children and parameters of the original node.
    • Fix the undo command in the Title List View so that deleted lines/nodes are properly restored.
    • When sorting nodes by fields, properly handle a reverse direction.
    • Fix problems with the find and replace command when a particular node type is specified.
    • Fix problems defining conditional types from the Configure Data Types dialog box.
    • Correctly apply font size formatting to selections with mixed font sizes.
    • Fix the height of long text field editors with customized data editor fonts.
    • Fix HTML export of Base 64 images.
      Missing Features (not implemented yet):
    • Support for plugin extension modules.
    • Language translations for the GUI and documentation.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    March 8, 2014 - Release 1.9.4 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It is not yet complete and could contain bugs. Testing and bug reports are appreciated.
    • The GUI and documentation translations have not yet been done.
      New Features:
    • Created new documentation, including a TreeLine file with details and a text file with basic usage instructions. Both are accessible from the help menu.
    • Added customizing of default fonts used in the tree, output and editor views.
    • Added a new SpacedText field type that holds plain text and preserves all spacing.
    • Combination and auto combination field types now use a simpler checkbox style pull-down editor.
    • An autosave option was added.
    • A unique ID reference field was added to the file info fields to allow node unique IDs to be included in output formats.
    • A plain text paste command was added to paste non-formatted text to data editors.
    • Added an option to set the child indent offset amount.
      Updates:
    • The last size and position of the print preview window are remembered and restored.
    • When printing, nodes with long text content are split between pages.
    • In multiple page HTML exports, relative links in the content are adjusted based on the directory depth.
      Bug Fixes:
    • Fixed problems outputting completely blank nodes.
    • Problems with the contains and true/false conditional rules were fixed.
    • Fixed issues displaying several editor link dialogs in quick succession.
    • In the configure data types dialog, the output format cursor no longer moves when switching to other field references.
      Missing Features (not implemented yet):
    • Support for plugin extension modules.
    • Language translations for the GUI and documentation.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    January 19, 2014 - Release 1.9.3 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It is not feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.4.x) should be used for critical work.
    • The documentation is not included yet. It needs to be updated to cover the new features.
    • The GUI and documentation translations have not yet been done.
      New Features:
    • Added controls in the Tools menu for customizing TreeLine's keyboard shortcuts.
    • Controls for customizing TreeLine's toolbar buttons were added to the Tools menu.
    • New dialogs were created for conditional finding and filtering of nodes. Specific conditions can be applied to individual types and fields, and the conditions can be saved.
    • Find and replace functionality was added to search and change nodes' text data. The search can be limited to specific types and fields.
    • A new option for output data in tables was added to the Type Config pane of the Configure Data Types dialog. Each line of the output format becomes a column. Any text at the start of the format line that is followed by a colon becomes a table heading.
    • An option to add bullets to the output of child nodes was added to the Type Config pane of the Configure Data Types dialog.
    • Added View > Previous Selection and Next Selection commands to step through the node selection history.
      Updates:
    • Nodes can now be reordered by dragging and dropping them between sibling nodes.
    • The keyboard entry of dates and times into fields was made more flexible by allowing entries such as 4-digit years that don't exactly match the entry format.
    • Any text selection is now used as the default name for links inserted into text fields.
    • Links to local named anchors in a node's HTML text content now work if they don't conflict with any node unique IDs.
    • Line spacing in output views was made more consistent.
    • Improved the efficiency of restoring node open/close states when opening files.
      Bug Fixes:
    • Errors when pasting text with varying font sizes into data editors were fixed.
    • Various issues with conditional data types were fixed, including problems with pasting conditional nodes and prompt updating when the types change.
    • Problems with undoing the dragging and dropping of a node were fixed.
    • Fix the extremely slow operation of the View > Expand Full Branch and Collapse Full Branch commands.
    • Fix improperly placed branch lines in printed output.
      Missing Features (not implemented yet):
    • Plugin support.
    • Language translations.
    • Help documentation.
    • Font appearance options for views.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    October 22, 2013 - Release 1.9.2 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It is not feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.4.x) should be used for critical work.
    • The documentation is not included yet. It needs to be updated to cover the new features.
    • The GUI and documentation translations have not yet been done.
      New Features:
    • Added a spell check tool. This requires either aspell, ispell or hunspell to be installed.
    • Included a node numbering field type with several formatting options. An update numbering command fills in the sequence.
    • Added a command to add a category level based on a subset of data fields.
    • Added a flatten by category command to combine parent fields into child nodes.
    • A new flatten by link command flattens the structure and provides internal links to the former parent nodes.
    • An arrange by link command restores the structure based on parent internal links.
      Updates:
    • Allow file URL drag-and-drop on active external link data edit widgets.
    • Change the Linux installer to use the 'share' directory in place of 'lib' for python files.
    • Update the Windows binary to use version 3.3 of Python.
      Bug Fixes:
    • Fix out of sequence output lines when output formats are longer than ten lines.
    • Fix problems with unique IDs and internal links when indenting and unindenting nodes.
    • Avoid widget focus problems when editing data on conditional types.
    • Maintain the output format cursor position when changing fields in the configure dialog.
    • Fix importing of generic XML documents that have nodes with no data.
      Missing Features (not implemented yet):
    • Plugin support.
    • Language translations.
    • Help documentation.
    • Font appearance options for views.
    • Previous/next selection history commands.
    • Customized keyboard shortcuts.
    • Customized toolbars.
    • Prefix/suffix sibling tags for HTML tables, bullets, etc.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be fully compatible with TreeLine 1.4.x.

    May 2, 2013 - Release 1.9.1 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It is not feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.4.x) should be used for critical work.
    • The documentation is not included yet. It needs to be updated to cover the new features.
    • The GUI and documentation translations have not yet been done.
      Updates:
    • Added TreeLine file compression and file encryption, controlled from a File > Properties dialog box.
    • Tree node open/close states are restored for recent files.
    • Added derived data types that keep the field list of their generic type.
    • Added conditional type setting that changes icons or output format based on field contents.
    • Other field references (file info, ancestors, children) can be used in node output formats and in print headers & footers.
    • Added an HTML file export to a single file with a navigation pane on the side.
    • Allow embedded blank lines in non-HTML node output formats.
    • Added an output separator config option for combination fields and child references.
    • Add an option to set the first day of the week for calendar widgets.
      Bug Fixes:
    • Fixed problems with pasting or dragging multiple nodes.
    • Made removing fields from multi-line output formats work properly.
    • Prevent duplicate unique IDs from being created after undoing the deletion of a branch.
    • Fixed node sorting of non-text nodes (numbers, dates, times, etc.)
    • Avoid placing calendar widgets partially off screen if near the bottom.
    • Limit the automatic height increases for text edit cells to avoid confusing double scroll bars.
      Missing Features (not implemented yet):
    • Plugin support.
    • Language translations.
    • Help documentation.
    • Spell checking.
    • Font appearance options for views.
    • Previous/next selection history commands.
    • Customized keyboard shortcuts.
    • Customized toolbars.
    • Automatic node numbering.
    • Prefix/suffix sibling tags for HTML tables, bullets, etc.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be compatible with TreeLine 1.4.x.

    February 6, 2013 - Release 1.9.0 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot of a full rewrite of TreeLine. It is far from feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.4.x) should be used for critical work.
    • The documentation is not included yet. It needs to be updated to cover the new features.
    • The GUI and documentation translations have not yet been done.
      Major New Features:
    • TreeLine has been fully rewritten using Python 3.
    • Improved performance due to direct use of model-view classes for views and ElementTree for input/output.
    • A table based data editor pane (much faster).
    • WYSIWYG formatting in the data editor view.
    • Real-time updates of the same file shown in multiple windows.
    • Improved printing and print preview performance.
    • Saves print options with the TreeLine file.
    • Built-in print to PDF function.
    • More searching options.
    • A filtering command shows matches in a simple list.
    • Sorting parameters can be saved with each data type.
    • The basic text field type allows formatting, preserves line breaks and allows HTML restricted characters.
    • A calendar widget can be used for editing date fields.
    • Internal link fields and inline internal links are easier to use.
    • An external link type supports http, https, file and mailto protocols.
    • Relative paths are supported for external links and pictures.
    • A regular expression field type can match patterns (phone numbers, email addresses, etc.)
    • Unique node IDs are automatically generated and updated.
    • A new windows installer allows a single-user, non-administrator install.
    • Includes better support for portable installs.
      Missing Features (not implemented yet):
    • File compression and file encryption.
    • Plugin support.
    • Language translations.
    • Help documentation.
    • Saving of tree open/close states.
    • Spell checking.
    • Font appearance options for views.
    • Previous/next selection history commands.
    • Customized keyboard shortcuts.
    • Customized toolbars.
    • Generic and derived data types.
    • Conditional type setting.
    • Automatic node numbering.
    • Other field references (file info, ancestors, children).
    • Prefix/suffix sibling tags for HTML tables, bullets, etc.
      Compatibility Notes:
    • There are some file format changes between TreeLine 1.4.x and this version of TreeLine.
    • Older files opened in this version are automatically converted when saved.
    • Files saved in this version may not be compatible with TreeLine 1.4.x.

    November 11 2011 - Release 1.4.1 (stable release)

      Bug Fixes:
    • Fixed failures due to bad internal references when opening encrypted files in multiple windows.
    • Avoid corruption of user option settings after attempting to automatically open an imported file as the last file used.
    • Fix problems with imported files when the user sets new files to be encrypted by default.
    • Prompt the user for a password when copying types from an encrypted TreeLine file.

    April 14, 2011 - Release 1.4.0 (new stable release)

      Notes:
    • This is a new stable release, ending the 1.3.x development series.
    • This release is available in English, French and German, although the French documentation is not completely up to date. Volunteers to do additional translations are welcome.
      Updates:
    • The file browser used for editing path-based fields now remembers the previously used directory.
    • Added icons for the New Window and Close Window commands so they can be added to toolbars.
      Bug Fixes:
    • Fixed a bug that could keep the column control from being enabled during HTML export.
      Major New Features Since 1.2.x:
    • Different files can be open in multiple TreeLine windows within the same TreeLine session. This is controlled with commands in the new "Window" menu.
    • The "Window->New Window" command creates a new window with views of the same TreeLine file. Changes in either window are saved in the same document.
    • Starting TreeLine (from a shortcut, file association or command line) will activate an existing TreeLine session if it is already running.
    • An "Add internal link" context menu has been added to text boxes in the data editor. It prompts for another node to be clicked with the mouse, then an inline internal link is added with that node's reference information.
    • Added an "HTML directory pages" export option. This will export a directory structure with an HTML file for every node. A navigation pane on the left side of each page contains links to nearby nodes.
    • New dialog buttons will restore the default configuration when customizing toolbars or shortcuts.
    • A new text search function has been added to the help viewer.

    January 5, 2011 - Release 1.3.5 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It may contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.2.x) should be used for critical work.
      Updates:
    • Incorporated some minor code clean-ups (thanks to Erik Wegner for identifying them).
    • The Windows binary is now based on the Python 2.7, Qt 4.7 and PyQt 4.8 libraries.
      Bug Fixes:
    • Fixed incorrect sorting by type with siblings of mixed types.
    • Fixed problems showing child lines in print previews if the lines option was changed with the preview open.
    • Really disable click-to-rename if the general option is unselected.

    September 22, 2010 - Release 1.3.4 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It may contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.2.x) should be used for critical work.
      Updates:
    • Added ico and gif as valid tree icon types.
    • The French GUI translation has been updated, but the documentation translation is still out of date.
    • Minor updates have been made to the German GUI translation.
      Bug Fixes:
    • The list of windows in the Window menu is now properly updated after saving a file with a new name.
    • Fixed a bug that could cause spell checks to hang.

    June 24, 2010 - Release 1.3.3 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It may contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.2.x) should be used for critical work.
    • German is the only GUI and documentation translation that has been updated so far.
      New Features:
    • A new text search function has been added to the help viewer.
    • The keyboard shortcuts for scrolling the right-hand views (Ctrl+Page Up and Ctrl+Page Down) now cycle through the Data Editor view pages if there is no more room to scroll
      Updates:
    • The Linux system requirements have been updated to indicate that Qt 4.4 or higher is now required.
    • The Windows installer now sets the sample and readme documents to read-only status.
    • The German GUI and documentation translation has been updated.
      Bug Fixes:
    • The cascading of new windows has been fixed. It now references the current position of the previous window, and it avoids cascading windows off of the screen.
    • The Data Editor widgets are now sized correctly when TreeLine is started in Data Editor mode.
    • The spell checker and the Linux installation script have been updated to avoid subprocess command depreciation warnings.

    May 14, 2010 - Release 1.3.2 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It may contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.2.x) should be used for critical work.
    • The GUI and documentation translations have not yet been updated.
      Updates:
    • Updated the ReadMe file to cover the new features added during this development cycle.
      Bug Fixes:
    • Fixed a major bug that prevented files from being saved at the "Save Changes?" dialog when closing a modified file.

    April 8, 2010 - Release 1.3.1 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It may contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.2.x) should be used for critical work.
    • The documentation has not yet been updated to cover the new features.
    • The GUI and documentation translations have not yet been updated.
      New Features:
    • Added a menu command that updates another window containing the same file (without waiting for a focus change). This command also has a keyboard shortcut (Ctrl+W).
    • A menu option has been added to hide the status bar. There is also a new general option to hide it at startup. A hidden status bar is automatically shown temporarily for important messages.
    • A new button on the toolbar editing dialog will restore the default toolbar configuration.
    • A new button on the keyboard shortcuts editing dialog will restore the default shortcut configuration.
      Updates:
    • Portability on Windows has been improved. A "treeline.ini" config file in TreeLine's "lib" directory will be used if it's present and there are no config files in the user's application data directory.
    • The Change Selected Data command has been updated to use Data Editor formats for dates and times.
    • An alternate TreeLine executable file (treeline_dos.exe) has been added to make batch command-line operations work from Windows.
    • Additional plugin methods have been added for handling files and languages.
      Bug Fixes:
    • Fixed a problem spell checking with older versions of aspell when Unicode characters were present.

    October 14, 2009 - Release 1.3.0 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.2.x) should be used for critical work.
    • The documentation has not yet been updated to cover the new features.
    • The GUI and documentation translations have not yet been updated.
      New Features:
    • Multiple TreeLine windows with different files can be open within the same TreeLine session. The "Open files in new windows" general option controls whether new windows are used when opening or creating files.
    • A "Window" menu has been added with commands to create new windows, close windows, or select from a list of current windows.
    • The "Window->New Window" command creates a new window with views of the same TreeLine file. Changes in either window are saved in the same document. This can be used to work in different sections of the file simultaneously. For performance reasons, the non-active window does not show the changes made in the active window until the non-active window is focused.
    • Starting TreeLine (from a shortcut, file association or command line) will activate an existing TreeLine session if it is already running. A new window will be opened if an unopened file was specified by file association or in the command line.
    • An "Add internal link" context menu has been added to text boxes in the data editor. It prompts for another node to be clicked with the mouse, then an inline internal link is added with that node's reference information.
    • Added an "HTML directory pages" export option. This will export to a directory structure with an HTML file for every node. A navigation pane on the left side of each page contains links to the node's parent, uncles and children.
      Updates:
    • The general options dialog has been split into three columns for better viewing on small, wide displays.
    • Additional export commands and export options have been added to the plugin interface.
    • To avoid a problem on the Mac platform, when TreeLine is run for the first time, it lets the OS determine the window position.

    October 12, 2009 - Release 1.2.4 (stable release)

      Bug Fixes:
    • Added a work-around for a bug in PyQt 4.6's clipboard support that can prevent TreeLine from starting.
    • Prevent an uncommanded horizontal scrolling to the left of the tree view when changing the selection.

    May 5, 2009 - Release 1.2.3 (stable release)

      Updates:
    • A new build has been created for use on the Windows 98 operating system. This fixes problems that made TreeLine 1.2.2 unusable on Windows 98.
    • Data copied to the Windows clipboard is now preserved after exiting from TreeLine.
      Bug Fixes:
    • Fixed a bug on Windows that showed an error message at program exit if the copy command had been used during the session.
    • In an HTML directories export, characters that are illegal in directory names are now correctly removed.

    January 8, 2009 - Release 1.2.2 (stable release)

      Updates:
    • Added German translations of the GUI and the ReadMe file.
    • Added a few missing strings to the translation files.
    • Substituted some imported modules to avoid deprecation warnings in Python 2.6. Note that Python 2.3 is no longer supported.
    • The windows binary has been updated to use Python 2.6, and the installer has been tweaked to reduce DLL conflicts.
      Bug Fixes:
    • Fixed problems using the tab key to change focus from the tree to the data editor.
    • ID numbers are now properly assigned to new nodes with UniqueID fields in the title.
    • Fixed problems creating nodes with child count fields in the titles.

    November 4, 2008 - Release 1.2.1 (stable release)

      Bug Fixes:
    • Fix the loss of entered text when the renaming of a node is ended by a command that changes the selected node.
    • Problems with opening files with Unicode file names from the command line or from a file association have been fixed.
    • Fixed problems with JPEG and GIF image support in the Windows binary build.
    • When commands change the tree view, it no longer scrolls vertically unless the current node is not visible.
    • Fixed problems with files set to both compressed and encrypted modes. But note that compressing an encrypted file still does not significantly reduce its size.
    • Problems on the Macintosh platform with detecting the text encoding and with setting the default theme have been fixed.

    June 17, 2008 - Release 1.2.0 (new stable release)

      Notes:
    • This is a new stable release, ending the 1.1.x development series.
    • This release is only available in English and French. The 1.0.2 release is still available, including German, Portuguese, Russian and Spanish translations. Volunteers to update the translations are welcome.
      Updates:
    • The French translations of the GUI and the ReadMe file have been updated.
      Bug Fixes:
    • When restoring an auto-saved backup file, TreeLine no longer replaces a the main file with the backup if the backup is not a valid TreeLine file.
    • Fixed a minor bug in the Configure Data Types dialog caused by unselecting a field in the Output pane.
      Major New Features Since 1.0.x:
    • TreeLine was extensively rewritten to port it to the Qt4 library (previous versions used Qt3.x on Linux and Qt2.3 on Windows). Benefits include updated widgets and removal of the non-commercial license exception in Windows.
    • Preformatted templates have been added for new TreeLine documents. User-created templates can also be added.
    • The content of right-hand views varies based on the selection and other options. A single selection still shows panes with the parent and its children, but a multiple selection will show all of the selected nodes in a single pane. Also, the Data Output view can optionally show an indented view of all descendants, and the Data Editor view splits the display into pages to speed up display.
    • More commands can make use of a multiple selection instead of just using the single active node. Also, an option can set the sequence of showing and exporting multiple selections to either tree order or selection order.
    • There is a tab on the left-hand view for a flat node list showing the selected nodes and all of their descendants. It is most useful for showing the results of filtering. There is a conditional filter for specific rules and a text filter that searches all fields for a string.
    • Several dialogs have been reworked for usability. The Configure Data Types and Print Options dialogs use tabs for better organization. The Configure dialog also has initially hidden advanced features and is now modeless, so it can be left open while applying configuration changes. The Sort, Export and Print Preview dialogs have also been updated.
    • Navigation through the tree is simplified by new commands that step through the selection history. Also, search strings are now highlighted in the Data Output view for text searches.
    • New dialogs have been added to customize keyboard shortcuts and tool bar buttons. There is also a directory for user-defined tree icons.
    • New file import and export options convert between an outline and an Open Document Format (ODF) text document, compatible with OpenOffice.org and KWord. Formatting is not maintained.
    • A Unique ID field type has been added that is automatically loaded with unique numbers. It is useful for link references.

    January 15, 2008 - Release 1.1.10 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is nearly ready to become a stable release, but it could still contain bugs. Testing and bug reports are appreciated.
    • The French translation of the GUI is the only one completed so far. None of the documentation translations have been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages may not be available yet for these libraries in some distributions.
    • If you've installed previous development releases, it is recommended that you delete the old configuration file ("~/.treeline-1.1/treelinerc" on Linux, "Documents and Settings\<login>\Application Data\bellz\treeline-1.1\treeline.ini" on Windows) before running this release.
      Updates:
    • Exporting to HTML directories has been improved. The file names are generated from the reference field (were from the first field). Internal links to nodes now work properly in the exported files.
    • When saving a new file, the Save-As dialog now defaults to the top directory in the recent file list.
    • A translation of the GUI in French is now available. The i18n installation file is a separate download.
    • The ReadMe documentation file has been updated to clarify certain usage issues.
      Bug Fixes:
    • The other controls in the configuration dialog are updated immediately when setting a data type to be derived from a generic.
    • A recent file list bug that affected the httpload plugin has been fixed. Also, a library need by the plugin (urllib) has been added to the Windows installation.
    • An error message about removing a status bar widget has been eliminated.
    • An error on a Mac when setting the language encoding has been fixed.
    • Various issues with file paths containing Unicode characters have been fixed.

    June 13, 2007 - Release 1.1.9 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It could contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.x) should be used for critical work.
    • The translations of the GUI and of the documentation have not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • If you've installed previous development releases, it is recommended that you delete the old configuration file ("~/.treeline-1.1/treelinerc" on Linux, "Documents and Settings\<login>\Application Data\bellz\treeline-1.1\treeline.ini" on Windows) before running this release.
      Updates:
    • Initially select the top filtering result in the flat view to avoid issues with a blank selection.
    • Avoid entering rename mode when clicking on a multiple selection in the flat view.
    • Maintain the size of the type icon dialog during a session.
    • Remove the redundant printing units option from the general options dialog.
    • Extensively update the ReadMe documentation to match the current feature set.
    • Add a new file template for TODO lists.
      Bug Fixes:
    • Fix incorrect internal references in groups of pasted nodes.
    • Abort a tree rename operation if the new name does not match the title format.
    • Correctly add a field to the generic type when numbering a derived type.
    • Properly update the pull-down choices for a choice or combination field after a configuration change.
    • Enable the conditional type button immediately after defining a type as derived.
    • Remove the page number field from the available file reference fields in the main configuration settings.
    • Properly update the Data menu after starting a filtering operation.
    • Fix an error due to a missing system language setting.
    • Properly handle a file open error due to an unknown field type.

    June 1, 2007 - Release 1.0.2 (stable bug-fix release)

      Updates:
    • The environment variable LC_MESSAGES is now checked before the LANG variable to determine the user's preferred language.
      Bug Fixes:
    • Problems with automatically adding a new field to derived data types when using the Data->Numbering and the Data->Flatten... commands have been fixed.
    • Fixed a crash at file open if the file's owner is not found in a Linux machine's user password database.

    May 22, 2007 - Release 1.1.8 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.x) should be used for critical work.
    • The documentation and GUI translations have not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • If you've installed previous development releases, it is recommended that you delete the old configuration file ("~/.treeline-1.1/treelinerc" on Linux, "Documents and Settings\<login>\Application Data\bellz\treeline-1.1\treeline.ini" on Windows) before running this release.
      Updates:
    • Translation of ODF text documents has been added to the command line batch processing options.
    • The environment variable LC_MESSAGES is now checked before the LANG variable to determine the user's preferred language.
      Bug Fixes:
    • Problems writing the options file when there are Unicode characters in the username have been fixed.
    • Various minor bugs in Unicode handling have been fixed.

    May 3, 2007 - Release 1.1.7 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.x) should be used for critical work.
    • The documentation and GUI translations have not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • If you've installed previous development releases, it is recommended that you delete the old configuration file ("~/.treeline-1.1/treelinerc" on Linux, "Documents and Settings\<login>\Application Data\bellz\treeline-1.1\treeline.ini" on Windows) before running this release.
      New Features:
    • Preformatted templates have been added. The File->New command brings up a dialog with a list of available templates. The dialog is also shown at startup if the recent file list is empty. Default templates are installed into TreeLine library directories. New templates can be added to a user templates directory in the user settings location. Template file names consist of a number for sorting, a language code and the name of the template.
      Updates:
    • The Save As dialog in Windows is now the native dialog.
      Bug Fixes:
    • Problems exporting to an ODF text document when blank fields are encountered have been fixed.
    • Added appropriate error messages to the Linux installer if some installer files are not found.

    April 17, 2007 - Release 1.1.6 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.x) should be used for critical work.
    • The documentation and GUI translations have not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • If you've installed previous development releases, it is recommended that you delete the old configuration file ("~/.treeline-1.1/treelinerc" on Linux, "Documents and Settings\<login>\Application Data\bellz\treeline-1.1\treeline.ini" on Windows) before running this release.
      New Features:
    • A new command (View->Show Output Descendants) toggles the Data Output child view from showing only child nodes to showing an indented view of all descendant nodes. A button was added to the default toolbar for this command. Also, a new general option can make the descendant view the default at startup.
    • A new file export option converts an outline to an Open Document Format (ODF) text document, compatible with OpenOffice.org and KWord. The title of each node is assigned a heading style at the appropriate level. Any other text in the output of each node becomes normal text under the heading. Any HTML formatting is stripped.
    • ODF text documents can be imported. The node structure is based on the heading styles assigned in the document. Any text under each heading is assigned to that heading's node. Formatting is not maintained.
      Updates:
    • New commands were added to the Data Editor context menus that open the Configure Data Types dialog with the editor's type and/or field already selected.
    • Keyboard shortcuts were added for the commands that add HTML tags in the Data Editor. Icons were also added to these commands, so the toolbar editor can be used to place them on a toolbar if desired.
    • The interface for writing plugin modules was improved by adding interfaces to the keyboard shortcut editor and the toolbar editor. Also, a plugin interface to get the plugin's directory was added.
    • Any default text for new fields is added when a node's data type is changed (not just to a new node), as long as there isn't already data in a field with the same name.
      Bug Fixes:
    • Fixed a problem with the automatic opening of the last file used if there are no valid recent files.
    • Fixed a crash at file open if the file's owner is not found in a Linux machine's user password database.
    • Issues with the display of text have been fixed if the Qt library being used is version 4.2.3 or greater (the Windows build now uses 4.2.3). These issues showed up when scroll bars were shown and could hide the right edge of the text or the last line.
    • Multiple issues with dragging or pasting nodes between sessions of TreeLine were fixed.
    • If the Configure Data Types dialog is open, it is properly updated after the use of the undo command.
    • The find dialog is properly focused when repeatedly shown.
    • Fixed problems occurring when attempting to print an empty branch or an empty selection.
    • Fixed problems with the export of HTML directories. It now removes illegal characters from directory names created from field contents.
    • Auto choice fields are now properly updated after configuration changes.
    • A missing help menu was added to the Unique ID field format editor.

    March 8, 2007 - Release 1.0.1 (stable bug-fix release)

      Updates:
    • A Russian translation of the GUI and ReadMe file has been added. As a result, there are now six supported languages (English, French, German, Portuguese, Russian and Spanish).
      Bug Fixes:
    • Fixed a problem using drag & drop on a node with a conditional type.
    • Avoid problems caused by using the Edit->Cut command with the root node included in the selection.
    • The importing of files with bad Unicode characters has been improved.

    February 22, 2007 - Release 1.1.5 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and probably contains bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.0) should be used for critical work.
    • The documentation and GUI translations have not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • If you've installed previous development releases, it is recommended that you delete the old configuration file ("~/.treeline-1.1/treelinerc" on Linux, "Documents and Settings\<login>\Application Data\bellz\treeline-1.1\treeline.ini" on Windows) before running this release.
      New Features:
    • A Unique ID field type has been added. The field is automatically loaded with unique numbers. Initially, the field's format string is set to the desired first number in the series, with optional leading zeros and optional leading or trailing characters. All nodes of the data type will get an automatically assigned ID. The field format string will always show the next available number, which will be given to the next new node of that type.
    • The node sorting commands have been consolidated into a single new dialog. This provides more options for selecting what to sort (all nodes, branches, children or siblings) and how (by types and fields or by titles).
    • An option has been added to the numbering dialog to only number nodes where the number field already exists. This allows node types in the branch that do not have the number field to be skipped.
      Updates:
    • The tree view no longer scrolls horizontally when the selection is changed.
    • The focus behavior of the Data Editor view has been tweaked to allow easier tabbing between widgets.
    • Clicking on a selected node to rename it is now disabled when multiple nodes are selected. This avoids initiating a rename when the intent was to modify a multiple selection.
    • The Insert Sibling Before command has been added to the node right-click context menu for consistency.
    • The Spell Check dialog is no longer hidden and re-shown between each misspelled word, resulting in smoother operation.
    • The Output tab of the Configure Data Types dialog has been adjusted to avoid changing the dialog size when toggling the advanced options.
    • The fonts in the Print Options dialog are sorted case insensitively, and the size of the dialog is fixed regardless of the selected font.
      Bug Fixes:
    • Fixed a crash when opening a file with the flat view shown.
    • Fixed problems occurring when the number of toolbars was set to zero.
    • Fixed undo operations for Numbering, data Add Category Level and Arrange by Reference commands.
    • Fixed problems with undo and delete commands issued while a node is being renamed.
    • Fixed problems with renaming data types and fields in the Configure Data Types dialog.
    • Avoid adding duplicate types to Other Field References in the advanced Output tab of the Configure Data Types dialog.
    • No longer allow the Edit Cut command to operate if the root node is selected.
    • Fixed a freeze of the spell checker on some platforms.
    • An empty rectangle that was sometimes shown on the status line at the bottom of the main window has been removed.
    • An occasional problem with the import of generic XML was fixed.
    • The importing of files with bad Unicode characters has been improved.
    • The restoring of tree states when opening a file has been made more robust.
    • Fixed several other minor tracebacks that can show up in a terminal or log file.

    January 18, 2007 - Release 1.1.4 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and is sure to contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.0) should be used for critical work.
    • The documentation and GUI translations have not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
      New Features:
    • Previous and Next Selection commands have been added to the View menu. These commands step through a history of tree selections for quicker navigation.
    • When using the Find command with the Data Output view visible, the search string occurrences are highlighted in the output. Note: in Linux, this feature requires Qt v4.2 or greater and PyQt v4.1 or greater.
    • An icons directory has been added to the user configuration directory ("~/.treeline-1.1/icons" on Linux, "Documents and Settings\<user>\Application Data\bellz\treeline-1.1\icons" on Windows). Image files (PNG or BMP) placed into this directory are available for use as tree icons.
    • "Move First" and "Move Last" commands have been added to the Edit menu. These commands move a child node to be the first or last child of its parent.
      Updates:
    • Horizontal scrolling of the tree view when the contents are wide is now supported.
    • The non-interactive command line options have been ported from the stable version. These options allow batch processing of file imports and exports.
    • Support for plugin extension modules has been ported from the stable version. The interfaces to TreeLine functions are unchanged, but existing plugins will need to be ported to the Qt4 library. An updated version of the httpLoad plugin is available.
    • A plugins directory has been added to the user configuration directory. This allows plugin installation without elevated privileges.
    • The code required to support GUI translations has been ported from the stable version, but the actual translations have not yet been updated.
      Bug Fixes:
    • The problem with cut/copy/paste operations in Windows that produced an error message at application exit was fixed.
    • Fixed several problems with the undo of changes to the Data Type Configuration.
    • A bug that could sometimes add an extra node during renaming in the Tree View has been fixed.
    • Problems encountered when typing a replacement word during spell check have been fixed.
    • A spell check language setting in File Options that is not available on the system is now ignored.

    December 21, 2006 - Release 1.1.3 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and is sure to contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.0) should be used for any critical work.
    • Some features from the stable release are not yet implemented here. These include command line options, plugin support and translation support. Also, the documentation has not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • One known bug in the Windows version produces an error message at application exit if cut/copy/paste operations were done during the session.
      New Features:
    • A new built-in editor for keyboard shortcuts has been added to the Tools menu. It has two tabs: one for menu commands and one for other commands. Simply press the desired key combination to change the shortcut in the selected entry. In general, printable characters without Ctrl or Alt modifiers should not be used for shortcuts. Although the editor will accept them, they may not work properly when certain widgets are focused.
    • A dialog to customize the tool bars has been added. It is accessed from the Tools menu. This allows the user to select small or large icons, define the number of tool bars, and define the commands included in each tool bar.
      Updates:
    • The saving of node open/close states for recently opened files has been ported from the stable version.
    • The restoring of splitter sizes and the active right-hand tab from the previous session has been ported from the stable version.
    • The TreeLine configuration files now include a version number (.treeline-1.1 on Linux, treeline-1.1.ini on Windows) to avoid incompatibility issues with previous versions.
    • The default non-menu keyboard shortcuts have been changed to control-key sequences that function regardless of the focused widget.
    • The incremental node title search has been ported from the stable version. The default keyboard shortcut is now Ctrl+/.
    • The option to add a node when pressing the enter key has been ported from the stable version.
      Bug Fixes:
    • Searching for nodes with the flat view active now only finds nodes actually present in the flat view.
    • Problems with drag & drop of nodes with Unicode content were fixed.
    • The Icon Selection dialog under Configure Data Types now scrolls to the currently selected icon when opened.

    November 22, 2006 - Release 1.1.2 (unstable development snapshot)

      Notes:
    • All of the notes listed for Version 1.1.1 still apply.
      Bug Fixes:
    • Fixed a serious bug that caused TreeLine to crash when using a pull-down combo box on a field in the Data Editor view.

    November 21, 2006 - Release 1.1.1 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and is sure to contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.0) should be used for any critical work.
    • Several features from the stable release are not yet implemented here. These include keyboard shortcuts for non-menu items, command line options, plugin support and translation support. Also, restoring of tree node open/close states, window split locations and active tabs are not yet available. And the documentation has not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • One known bug in the Windows version produces an error message at application exit if cut/copy/paste operations were done during the session.
      New Features:
    • Printing functionality has been added to the development series. It now includes options to print the entire tree, the selected branches, or just the selected nodes.
    • A new Print Options dialog box is tabbed to give easier access to all of the options. There are buttons that give a more logical progression from the options to the print preview and to the print dialog.
      Updates:
    • The buttons at the bottom of the Configure Data Types dialog have been changed to OK/Apply/Reset/Cancel. This can reduce the number of mouse clicks.
    • The Configure Data Types dialog now defaults to the selected node's type when it is shown.
    • On Windows, the TreeLine.ini file has been moved from the installation directory to a location under the "Documents and Settings" folder. This avoids problems on multi-user systems and for users with limited access rights.
      Bug Fixes:
    • The Configure Data Types dialog now updates properly after copying types from another file, adding numbering, and rearranging by category and reference.
    • Various problems with node drag & drop that could result in inadvertent drops were fixed.
    • A bug that caused the right-hand view splitter to reset to even sizes was fixed.
    • Problems with saving changes to the format of file information fields were fixed.
    • Issues with some internal links and pictures in the help viewer were fixed.

    September 15, 2006 - Translation Updates

      Notes:
    • Spanish and Portuguese translations of the GUI and ReadMe file have been added for the stable version of TreeLine. A typo in the German translation was also fixed. The French translation remains unchanged.
    • The httpload plugin has been updated with French, German, Spanish and Portuguese translations.

    September 12, 2006 - Release 1.1.0 (unstable development snapshot)

      Notes:
    • This is an unstable development snapshot. It is not feature complete and is sure to contain bugs. Testing and bug reports are appreciated, but the stable release (TreeLine 1.0.0) should be used for any critical work.
    • Several features from the stable release are not yet implemented here. These include printing, keyboard shortcuts for non-menu items, command line options, plugin support and translation support. Also, restoring of tree node open/close states, window split locations and active tabs are not yet available. And the documentation has not been updated.
    • On Linux, running TreeLine requires Qt version 4.1 or higher and PyQt version 4.0 or higher. Binary packages are not yet available for these libraries in some distributions.
    • One known bug in the Windows version produces an error message at application exit if cut/copy/paste operations were done during the session.
      New Features:
    • TreeLine was ported to the Qt4 library. This involved a major rewrite of the code. The previous versions used Qt3.x on Linux and Qt2.3 on Windows. Benefits include updated widgets and removal of the non-commercial license exception in Windows.
    • The Configure Data Types dialog uses tabs for better organization. Many tabs contain advanced features that can be shown if desired. The dialog is also modeless, so it can be left open while applying configuration changes.
    • The content of the right-hand view varies based on the kinds of nodes selected. With a single parent node selected, it splits the view, showing the parent and its children (same as version 1.0.0). With a multiple selection or with a childless node selected, it shows all of the selected nodes in a single pane.
    • A general option sets the sequence for multiple selection to either tree order or selected order. When nodes are selected with control-click under the selected order option, they show in the right-hand view in the order they were picked. This sequence also applies to copy and export commands.
    • More commands make use of a multiple selection instead of just using the single active node. For example, the paste command will add duplicate children under each selected destination node.
    • The export command includes options to export the entire tree, the selected branches, or just the selected nodes.
    • In order to render the Data Editor right-hand view faster, there is a general option to set the number of "pages" initially shown. By default, only one page is shown. Buttons allow toggling to the next page or all pages.
    • There is a tab on the left-hand view to show a flat node list. It shows the initially selected nodes and all of their descendants. It is probably most useful when using filtering commands.
    • A conditional filter selects nodes based on rules for specific data types and fields, and a text filter selects based on finding the given text in any field. Both filters show their results in the tabbed "Flat View" and remain in effect until removed.
    • In the advanced mode, a child count field reference can be added to the output configuration. It shows the number of children at a specified descendant level.

    July 6, 2006 - Release 1.0.0

      Updates:
    • A new version numbering system is being introduced. This release is 1.0.0, to better indicate its stability. The 1.1.x series will be started soon for less stable development releases.
    • The German translation of the ReadMe file has been updated.
      Bug Fixes:
    • Fixed a problem with duplicate nodes showing up when pasting multiple nodes on Windows.
    • Deriving types from other derived types is no longer allowed, since it did not function properly.
    • A problem with saving an encrypted file in the German version of TreeLine has been fixed.

    February 16, 2006 - Release 0.14.1

      Updates:
    • Exported XSLT files now support field prefixes and suffixes. Thanks to Roland Meister for supplying patches.
    • Added functions to the plugin interface to allow plugins to open and close nodes.
      Bug Fixes:
    • Fixed a problem with displaying output from fields with non-ASCII characters in their names.
    • Auto save now works properly with encrypted files.
      Notes:
    • The French and German UI translation files and the French ReadMe files have been updated, but the German ReadMe files are not complete (but still usable). Updated files will be made available soon.

    December 20, 2005 - Release 0.14.0

      New Features:
    • Data types can be set to derive their field settings from a generic type. This allows types with different output formatting to always use the same field data. Any changes to the generic's list of fields and field types are automatically reflected in the fields of all derived types. A derived option can be selected when copying a type, or a generic type can be specified from the derived type's "Advanced Configuration" dialog box.
    • Conditional expressions can be used to automatically assign a data type based on each node's content. Conditions are assigned to a generic type and its associated derived types. This allows the automatic assignment of different output formatting or different icons depending on each node's field data. Conditions are specified from each type's "Advanced Configuration" dialog box. Conditions do not have to be set for all types in a family, since, if no conditions are true for a node, the program will select a blank condition over a false one. In addition, conditions that are always "True" or "False" are available to toggle the output format of all nodes of a certain type simultaneously by modifying the condition.
    • By default, the spell check uses dictionaries for the current operating system language. A new option under "Tools->File Options" can be used to specify an alternate two-letter language code for the current TreeLine file. This only works with aspell and with the appropriate aspell dictionaries available.
    • A new menu item, "File->Open Sample", is a shortcut to the directory containing sample template files.
    • A new menu item, "Help->Help Contents", directly opens the "Using TreeLine" section of the ReadMe file.
      Updates:
    • When changing a node's type, if the result would have been a blank title, TreeLine now adjusts the new title fields to maintain the original title text.
    • Picture links with relative paths now resolve their reference based on the directory containing the current TreeLine file.
    • When applying a font tag in the editor view, the selection is maintained. This allows multiple tags to be applied.
    • HTML tags in field prefixes and suffixes are now removed in node titles.
    • Exported HTML has been made somewhat more compliant with standards.
    • A new option on the windows installer toggles the writing of installation directory and uninstall information to the registry. When this and other options are disabled, TreeLine can be installed without modifying the registry.
    • Four more sample files have been included. These files provide examples of using TreeLine's features and can be used as templates.
    • The ReadMe file has been updated with descriptions of the sample files, with more internal links, and with screenshots.
      Bug Fixes:
    • A problem with saving reference field settings for unused node types was fixed.
    • Formats copied from another file are now available immediately.
    • Node titles from HTML-enabled fields that contain escaped characters (<, >, &) are now properly displayed.
    • Fixed some minor bugs concerning setting the default field value for new nodes.
    • A problem with exporting HTML directories with very recent versions of the PyQt library was fixed.
    • When displaying child data in node output, extra separators between blank entries are no longer shown.
      Notes:
    • The French and German UI translation files have been updated, but the French and German ReadMe files are not complete (but still usable). Updated files will be made available soon.

    November 4, 2005 - German Translation Update

      Notes:
    • Updated German translations are now available on the download page.

    November 1, 2005 - Release 0.13.1

      New Features:
    • The number of recently used files listed in the File menu can be set using a new general option. Note that this also controls how many files have their tree states (open/closed nodes, etc.) saved.
      Updates:
    • TreeLine now sets the interface language using the LANG environment variable (if set) before falling back to other locale settings. This allows the operating system's locale settings to be overridden.
      Bug Fixes:
    • Problems starting TreeLine when the locale's LANG variable ends with "@euro" have been fixed.
    • Problems with the display of the rename edit box when creating new nodes in a long, scrolled tree view have been fixed.
      Notes:
    • The French translation files have been updated, but the German files are not complete (but still usable). Updated files will be made available soon.

    August 29, 2005 - Release 0.13.0

      New Features:
    • The TreeLine user interface and documentation have been internationalized. Currently, translations are available for French and German. Volunteers to translate into additional languages are welcome.
    • Number formats can be internationalized. Periods and commas are supported as radix characters, and commas, periods or spaces can be set as thousands separators.
    • A new general option can set printing units to either inches or centimeters.
    • An external editor can be invoked from a Data Editor text field context menu. The EDITOR environment variable can be used to specify the editor to start, or, if the variable doesn't exist, TreeLine will prompt for an executable to set as the default.
      Updates:
    • The general option for a number editing format has been removed. Instead, the output format is displayed in the editor. Of course, any new entry with a reasonable format is correctly interpreted (but the correct radix character must be used).
    • Handling of spaces in filenames for the linking fields have been improved. Paths with spaces selected in the file browser are properly quoted (Windows) or escaped (Linux).
    • Page Up/Down commands in the Data Output view now leave a one-line overlap.
    • A Ctrl-C interrupt in a terminal is now ignored.
      Bug Fixes:
    • A dummy field has been added to imported bookmark separator formats to avoid configuration problems.
    • Paths in links to XSLT files are now properly handled when not in the same directory as the XML file.
    • Format text is now immediately updated when renaming fields.
    • Problems with undo after complex data changes have been fixed.
    • Errors due to having ASCII control characters in TreeLine text have been fixed.
    • Problems with spell check of unicode characters have been fixed.

    May 4, 2005 - Release 0.12.0

      New Features:
    • A new AutoChoice field type provides pull-down selection of previously used entries. Any new entries are automatically added to the pull-down.
    • A new ExecuteLink field type runs an external program when its link is clicked. The command to run is given by the text of the field. Or the field's prefix may contain the program name, so that the field's text is used for arguments or file names. There is also a general option to disable these links when security is a concern.
    • A button that brings up a file browsing dialog has been added to the editor for Path, ExecuteLink and Picture field types.
    • Link fields can display alternate text in place of the target URL. This is done by specifying an alternate text field in the Advanced Field Format dialog.
    • Fields from child nodes can be embedded in their parent's output. Select a child reference from the Other Fields dialog. The child data is delimited with a separator string defined as a file option.
    • A new file option allows the removal of line breaks from each output line. This allows other HTML tags to be used to separate the output lines.
    • A "contains" rule to check for substrings has been added to the rules for node filtering and selective type changes.
    • The right-hand view that was previously used is now selected automatically on startup. This can be disabled using the general restore window geometry option.
      Updates:
    • Toolbar and tree icons are loaded from individual PNG files instead of from an XPM file. This improves icon quality.
    • Some features from the dialogs for data types and fields have been moved to advanced dialogs for simplicity.
    • Unicode characters are accepted for first-letter tree searches.
    • All calls to the eval() function have been replaced for improved security. Thanks to Roland Meister for providing patches.
    • The HTML version of the ReadMe file is now exported from the TreeLine version.
    • Spaces are permitted in Linux command line arguments.
    • Qt command line options are supported.
    • There have been several minor improvements to the plugin module interface.
      Bug Fixes:
    • A serious problem with deleting the last child under the root item has been fixed.
    • Some keyboard shortcuts for incremental searching have been fixed.
    • Open nodes are restored more consistently when opening files.
    • A font issue on early versions of Qt3 has been fixed.
    • The search for dtd files linked from XML files has been disabled to eliminate errors.
    • Visibility problems with long unbroken text lines in data editors have been fixed in Qt3.

    February 16, 2005 - Release 0.11.1

      Bug Fixes:
    • Fixed a compatibility issue in the toolbar code that would prevent TreeLine from starting when PyQt was built against the newest versions of the sip library (versions 4.2rc1 and 4.2rc2).
    • Problems with editing the data of combination field types have been fixed.
    • A bug in the plugin interface for setting field formats has been fixed.

    February 4, 2005 - Release 0.11.0

      New Features:
    • Icons have been added to the tree view. The icon assigned to each data type can be changed from the Configure Data Types dialog box. There are several generic icons available within TreeLine, and plugin modules can be written to add additional ones. A general option to disable the tree icons has also been added.
    • A command has been added to the data menu to copy type formatting from another TreeLine file. All types from the chosen file are copied. Any types in the current file with a matching name are overwritten, but types with unique names are retained.
    • Functions to import and export generic XML files have been added. These routines do not have much intelligence - each XML element becomes a node and each XML attribute becomes a field. This lets TreeLine function as a crude XML editor.
    • An editor height parameter has been added to text fields. This allows the number of lines in the data editor to be set for each field in each data type. As a result, the LongText field type becomes redundant and has been removed.
    • A field parameter has been added for fields that are required to be filled. Fields with this parameter set are marked with an asterisk in the data editor view.
    • Another field parameter has been added to allow certain fields to be hidden in the data editor view.
      Updates:
    • A fair amount of TreeLine code has been rewritten to improve efficiency and to ease future changes. Users should see improved speed with large files, especially noticeable when repainting during editing.
    • TreeLine now requires Python Version 2.3 or higher on Linux systems. The previous version of TreeLine will remain available for those stuck with older versions of Python.
    • HTML tags are now stripped from node titles in the left-hand tree view if the fields are set to output HTML rich text.
    • The plugin extension module interface has been expanded. Several added functions deal with node and field formatting. There is also a new callback trigger called whenever a node's data is modified.
    • A user plugin directory can now be specified in the configuration file. This allows plugins to be installed without root/administrator access.
    • An option has been added to the Linux installer to allow a different documentation directory to be specified.
      Bug Fixes:
    • Fixed a drag-and-drop bug that wouldn't allow nodes to be moved instead of copied in the Linux version.
    • Fixed the output of fields that include dashes and periods in their names.
    • A problem retaining the font setting for edit views has been fixed.
    • A rare startup failure due to problems with the encryption engine has been fixed.
    • A rare problem with foreign language encodings has been fixed.

    November 8, 2004 - Release 0.10.2

      Bug Fixes:
    • Fixed a major bug that could prevent new nodes that contain date or time fields from being created.

    October 28, 2004 - Release 0.10.1

      Bug Fixes:
    • Fixed a major bug that caused TreeLine to hang when attempting to open a recent file that no longer exists. This bug also caused startup failures if automatic opening was enabled with nonexistent files.
    • A bug in the plugin interface's getRootNode function was fixed.
    • Fixed a problem with file encryption on 64-bit systems.

    October 15, 2004 - Release 0.10.0

      New Features:
    • One of the fields in a data type can be tagged as a reference field in the field-type dialog box. It defaults to the first field. This field is now used as the reference for the arrange and flatten by reference commands. It is also used by the new internal link feature, described below.
    • There is a new internal link field type. It creates a clickable link in the Data Output window that selects the next node with matching text in its reference field. If link or reference fields contain multiple lines, each line is treated as a separate link or reference, respectively. If desired, the same field can be used as both the link and reference fields, so that clicking on a keyword in one node's field selects the next node that also has that keyword. If exported to HTML, the internal links function as links to page anchors, but, in cases with duplicate references, they only find the uppermost reference on the page instead of the next one.
    • File encryption has been added as an option to password protect TreeLine files. Individual files can be set to encrypted mode from either "Tools->File Options" or from the save-as dialog. There is also a general option to set the default for new files. The encryption uses the SHA hash function as a stream cipher - it should be fairly secure.
    • A default initial field value can now be specified for a field type. Any new nodes get this value for the given data field when they are created. Also, in date and time fields, an initial value of "Now" can be used to get a time-stamp of node creation.
    • An interface to plugin extension modules has been added to TreeLine. This allows extensions to be written by various coders that provide functionality needed by a few users without adding bloat to the main application. Currently available plugins are listed on the "Downloads" page of the TreeLine web site. The plugins are installed by copying their Python file (*.py) to the plugins directory ("<prefix>/lib/treeline/plugins/" on Linux or "TreeLine\lib\plugins\" on Windows). A list of loaded plugins can be found using the "Help->About Plugins" command. Information about writing plugins can be found in the "plugininterface.py" file in the TreeLine source code.
    • Options have been added under "Tools->General Options" to set the fonts used for the tree view and for the right-pane editor views.
    • When printing, TreeLine will now avoid breaking pages between a parent and its first child. This behavior can be disabled by changing the "Keep first child with parent" print option.
      Updates:
    • Unicode text handling has been improved. Unicode can now be used in TreeLine file names, node data type names and field names. Also, imported and exported text files now use the proper encoding based on the system's locale settings.
    • A new sample TreeLine file with internal link fields has been added to the documentation.
      Bug Fixes:
    • An occasional problem bringing up the field-type dialog for file-info fields was fixed.
    • Avoid showing an oddly-named internal file-info data type in the dialogs after the file-info format is changed.
    • The option to restore the view state when opening recently used files now works more consistently.

    September 16, 2004 - Release 0.9.1

      Updates:
    • Unicode text is now supported without requiring modifications of the Python sitecustomize file. The sitecustomize change has been eliminated from the installer.
    • The compressed ".trl.gz" extension has been added to the file open filter.
    • Information about the new TreeLine mailing list has been added to the documentation.
      Bug Fixes:
    • A bug that prevented XSLT file export under Linux has been fixed.
    • Special characters in bookmark URL's are now properly escaped during export to XBEL format.

    September 9, 2004 - New Mailing List

    A mailing list has been created for users to discuss anything and everything about TreeLine. This is the place for development discussions (from roadmaps to feature suggestions to beta testing), release announcements, bug reports, and general user discussions (from new uses to tips & tricks to configuration samples).

    To subscribe, go to this page. I expect this to be a low-volume mailing list.

    September 1, 2004 - Release 0.9.0

      New Features:
    • Import and export of bookmarks in both the Mozilla HTML format (Mozilla, Firefox and Netscape browsers) and the XBEL format (Konqueror, Galeon and Elinks browsers) have been added.
    • An new option exports a portion of a tree to another TreeLine file.
    • Command line options have been added to allow non-interactive file importing and exporting. This allows automated runs to be scheduled. For more details, run "treeline -h" from the command line. If using a windows binary, output is supressed, so it must be directed to a log file ("treeline -h > log.txt").
    • Options have been added to work with compressed TreeLine files. Individual files can be set to compressed mode from either "Tools->File Options" or from the save-as dialog. There is also a general option to set the default for new files. Thanks to Mathieu Girard for contributing code.
    • A field reference to show data from any ancestor node has been added. The closest one with a matching field is used.
    • Fields containing file meta-data have been added. These include file name, path, size, and modified time.
    • Headers and footers for printing have been added. They can contain the file meta-data mentioned above. The headers and footers can also be shown in exported HTML files.
    • HTML character formatting tags can be automatically added to text using a new data editor context menu. Available tags include bold, italics, underline, size and color. Note that the fields must be set to display HTML content for this to be effective.
    • A new general option makes new fields default to HTML content. This allows for easier display of HTML formatting. This option is not enabled by default, since it does not preserve carriage returns and does not show non-escaped "<", ">" and "&" symbols.
    • When opening a recently used file, TreeLine will now restore the states of open and selected nodes. If desired, this feature can be disabled with a new general option. Thanks to Jan Hustak for contributing this code.
    • The toolbar has been split into two separate bars (general commands and node commands) that can be shown and moved independently. Again, thanks to Jan Hustak for contributing this code.
    • A new auto-save feature stores unsaved files with a "~" appended to the name. The backup files are automatically removed when the file is saved or TreeLine exits cleanly. The auto-save time interval is set in the general options.
    • New key bindings, set to Shift+Page-Up and Shift+Page-Down by default, scroll the current right-hand child view.
    • The XSL export command now prompts for the name of an optional style sheet (css). This name is stored in the TreeLine file as the default for future exports.
      Updates:
    • There have been some general improvements to the handling of imported and exported files.
    • File option settings can now be restored with undo/redo commands.
    • The README documentation files have been revised to be more organized and readable.
    • More sample files are provided. See the "sample_*.trl" files in the "doc" directory of the installation.
    • The Linux install script now includes an option for a temporary build root directory.
      Bug Fixes:
    • The up-arrow key binding did not work as expected in a deeply nested tree.
    • Some problems with auto-completion on data editor combo boxes have been fixed.
    • Problems in windows with some option spin boxes accepting new values have been fixed.
    • Fixed a compatibility issue with older versions of Python.

    June 23, 2004 - Release 0.8.1

      Bug Fixes:
    • Fixed crashes that sometimes occurred when switching focus or views after renaming a new or existing node.
    • Fixed a compatibility issue with older versions of Qt (3.0.x).

    June 3, 2004 - Release 0.8.0

      New Features:
    • Added undo and redo commands and an option for the number of undo levels that are stored.
    • Added the ability to show parent and grandparent data within a node's formatted output.
      Updates:
    • When changing node types with the menu, check marks now show the current type(s).
      Bug Fixes:
    • Fixed crashes caused by right-clicking in the edit area or using the Alt-Tab key combination when renaming a node title.
    • Fixed problems occurring when several similar data type names were defined.
    • A rare problem with the installation script choking on image thumbnail directories was fixed.

    May 18, 2004 - Release 0.7.3

      New Features:
    • Spell checking of the tree data has been implemented. This feature requires an external program, either aspell or ispell (see the System Requirements section).
      Updates:
    • The size and position of the print preview window are now saved.
    • Added an option for including only open descendants when exporting tabbed title text.

    April 1, 2004 - Release 0.7.2

      Updates:
    • For faster keyboard navigation, the left arrow key now closes the selected node's parent if the selected node has no children or is already closed.
      Bug Fixes:
    • Some tree item drag-and-drop bugs have been fixed.
    • Problems when some dialogs were closed using the escape key have been fixed.
    • Fixed some rare Linux install script problems with some systems.

    March 9, 2004 - Release 0.7.1

      Updates:
    • The open file dialog now uses the directory of the most recently opened file as its initial directory.
    • To improve performance, some unnecessary refreshes of the right-hand view were eliminated.
      Bug Fixes:
    • Fixed problems with repeated uses of the search dialog command and the command to set the types of descendants.
    • Fixed problems with the data editor view in the mode that does not show children.

    March 2, 2004 - Release 0.7.0

      New Features:
    • Added prefix and suffix tag formatting for groups of siblings. These tags allow output to be formatted in tables or with bullets. See the "sample_table.trl" file for an example of table formatting.
    • The size and position of the window and its splitters are now saved at exit. A new option will disable this feature if desired.
    • An import filter has been added to open Treepad files (text nodes only).
    • An install program has been added for windows.
      Bug Fixes:
    • Fixed Linux install script problems with certain versions of Python.
    • Fixed some text exports where improper end-of-line characters were used on windows.

    November 19, 2003 - Release 0.6.2

      Updates:
    • Cursor changes were added to indicate time-consuming operations.
      Bug Fixes:
    • Eliminated inadvertent scrolling of the tree view when editing in the right-hand view.
    • Fixed problems encountered when the Linux install script attempted to delete old TreeLine directories under certain versions of Python.

    November 7, 2003 - Release 0.6.1

      New Features:
    • Incremental searching has been improved by adding keyboard commands to repeat the search forward (F3 by default) and backward (Shift-F3 by default).
    • The sorting commands now contain options for reverse sorting.
    • The importing of text files has been improved. Imports of plain text were added, with items for each line or each paragraph. A prompt for the type of text file was also added.
    • A new option setting avoids going into title renaming mode when adding a new node. This also keeps the selection unchanged as nodes are added.
    • Dragging files to the TreeLine window in order to open them is now supported.
      Updates:
    • The rename command was added to the tree context menu.
    • The right view now scrolls to the top when the item selected in the tree view changes.
    • When opening the configure types dialog, the current tree item's type is initially selected.
    • A TreeLine formatted version of the ReadMe file has been added.
    • An install script was added for Linux and Unix systems.
    • The windows build now uses Python version 2.3 and PyQt version 3.8.
      Bug Fixes:
    • Keyboard commands are disabled during tree rename operations to avoid unpredictable results.
    • The right views now update properly when the parent of the selected tree item is closed.
    • Problems involving copying with multiple nodes selected were fixed.
    • Problems with drag-and-drop on some Linux systems were fixed.

    September 16, 2003 - Release 0.6.0

      New Features:
    • The three right views are now divided into upper sections for the selection's data and lower sections for the data from the selection's children. View commands can be used to hide the display of children if desired.
    • Keyboard shortcuts can be customized by editing the TreeLine configuration file ("~/.treeline" on Linux, "treeline.ini" on windows). Any configuration files from previous versions should be deleted when installing TreeLine 0.6.0.
    • A new command will quickly set a node's data type.
    • Parent nodes will automatically open and close when found with the two search methods, by typing the first letter and with the "next sibling" keyboard command. This behavior can be disabled with a new general option.
    • Typing a lowercase letter will move forward through the visible tree items that start with that letter. An uppercase letter will move backward.
    • Tree items (including those not visible) can be incrementally searched by typing "/" followed by the search string.
    • The Find dialog box is now modeless (the program may be operated while the dialog is open).
    • A "Choice" field type has been added that allows selection from a user-defined list of strings.
    • A "Combination" field type has been added that allows selection of several items from a user-defined list of strings.
    • Several linking field types have been added, including "URL", "Path", "Email", and "Picture". Clicking on a "URL" or "Path" in the output window will open the link in an external browser. The "Picture" fields are shown on in the output window for certain image formats.
    • Pull-down editors have been added for the "Choice", "Combination", "Date", "Time", and "Boolean" field types.
    • A font selection for the data output view has been added to the general options.
    • New printing options include setting the print font and setting a default page size.
      Updates:
    • Configuration information is properly saved for unused node data types.
    • TreeLine is now more keyboard-friendly in many ways.
    • Window captions now put the file name first.
      Bug Fixes:
    • Fixed problems with data edit view resizing (on Qt3 only).
    • Fixed file corruption problems caused by the use of HTML characters in the field format's prefix and suffix areas.

    March 14, 2003 - Release 0.5.0

      New Features:
    • When configuring node data types, a default type for that type's new children can be set.
    • An added form of HTML export creates a directory structure with a separate page for each parent node.
      Updates:
    • A shortcut (Ctrl-B) has been added to the command to insert a sibling node.
    • Icon files have been added to the distribution files.

    August 26, 2002 - Release 0.4.2

      Bug Fixes:
    • Fixed another (oops) incompatablity problem with Python 2.1.x. This change is also not needed when using Python 2.2 or higher.

    August 23, 2002 - Release 0.4.1

      Bug Fixes:
    • Fixed an incompatablity problem with Python versions 2.1.x. This change is not needed when using Python 2.2 or higher.

    August 22, 2002 - Release 0.4.0

      New Features:
    • Data fields can be formatted as specific types, including short and long text, numbers, dates, times, and boolean values.
    • Individual fields can be specified as plain text or HTML. Line breaks are preserved in plain text mode.
    • Text prefixes and suffixes can be assigned to fields. The extra text does not display for blank fields.
    • Options for spaces between nodes and allowing HTML in formats are saved with the file instead of being global options.
    • Node titles are truncated after the first line of text data.
    • Node types can be set conditionally.
    • A new option allows the number of lines in a long text edit field to be set.
    • Missing fields can be updated from a separate file by matching unique values of the first data field.
      Bug Fixes:
    • Clicking on an unselected current item no longer initiates title renaming.
    • Rare problems with opening or pasting content with complex text strings were fixed.

    May 28, 2002 - Release 0.3.4a

      Bug Fixes:
    • A fix of the Windows binary only. Fixes major problems by upgrading the library version to PyQt 3.2.4.

    May 15, 2002 - Release 0.3.4

      Updates:
    • TreeLine has been ported to Qt 3. It now works with both Qt 2.x and 3.x using the same source code.
    • The binaries for windows have been updated to Python 2.2 and PyQt 3.2 (but are still using Qt 2.3 Non-commercial).
      Bug Fixes:
    • A selection bug that caused problems with the up/down and indent/unindent commands has been fixed.
    • Errors in the initial user preference file were fixed.

    March 19, 2002 - Website Update

      This website now looks a little better. Hopefully, it's more user-friendly, too.
      Stay tuned - I'll soon be porting these programs to use PyQt with Qt 3.0.

    March 6, 2002 - Release 0.3.3

      New Features:
    • Multiple nodes in the tree can now be selected using the shift and control keys - most commands will operate on multiple nodes.
    • A new command will copy node titles as text, not just as XML.
    • Options have been added to print and export only nodes which are open in the tree.
    • A new option allows the numbering command to start with a number greater than one.
    • A tool to remove the XSLT reference from a file has been added.
      Updates:
    • The command to arrange a tree by reference has been made more robust.
    • Errors when opening files are now handled better.
      Bug Fixes:
    • The export of Unicode characters to HTML has been fixed.
    • A problem with the set data types dialog under Python 2.2 has been fixed.

    January 7, 2002 - Release 0.3.2

      New Features:
    • Unicode is now supported in both data and format strings, allowing the entry of foreign text and symbols (note that there is an extra step in the Linux installation to enable this feature).
    • A new sort command allows all nodes of a given type to be sorted.
    • A preference setting now controls the initial state of the right-hand view.
      Bug Fixes:
    • Fixed crashes caused by tool-bar use while renaming a node.
    • Occasional problems with deleting or renaming fields have been fixed.
    • Fixed crashes resulting from very large data edit views.

    December 12, 2001 - Release 0.3.1

      New Features:
    • Parent/child lines can now be added to printouts for better tree visualization.
    • An option was added to compress the format into a single line of output.
      Bug Fixes:
    • Problems with sorting full branches were fixed.
    • Fixed improper indentation on an HTML export file.

    November 27, 2001 - Release 0.3.0

      New Features:
    • Added filtering of descendant nodes.
    • Added a data node numbering feature with both outline and section styles.
    • Added a feature to export the format to an XSLT file.
    • Added table of contents links to the help file.
      Updates:
    • Improved the handling and editing of long data strings.
    • Improved the handling of HTML tags in data formats.
    • Improved XML parser error handling.

    October 23, 2001 - Release 0.2.1

      Bug Fixes:
    • Fixed a major bug that caused errors when new node types were created.

    October 17, 2001 - Release 0.2.0

      New Features:
    • TreeLine has been extensively rewritten to include database field information in each node.
    • The file format is now XML.
    • Added additional views in the right-hand pane.
    • Added options for data formatting and manipulation.
    • Added more file import and export options, including HTML export.
    TreeLine-3.2.1/docs/install.html000066400000000000000000000057251506556630100165300ustar00rootroot00000000000000 TreeLine - Installation
    TreeLine

    TreeLine Installation

    Linux

    Extract the source files from the treeline tar file, then change to the "TreeLine" directory in a terminal. For a basic installation, simply execute the following command as root: "python install.py"

    If your distribution defaults to Python 2.x, you may need to substitute "python3" for "python" in these commands.

    To see all install options, use: "python install.py -h"

    To install TreeLine with a different prefix (the default is "/usr/local"), use: "python install.py -p /prefix/path"

    To skip dependency checks, use: "python install.py -x"

    Windows

    To install for all users, execute the "TreeLine-x.x.x-install-all.exe" file. Administrator permissions are required.

    To install for a single user (administrator rights are not required), execute the "TreeLine-x.x.x-install-user.exe" file.

    For a portable install, execute the "TreeLine-x.x.x-install-user.exe" file. The file association, shortcuts and uninstaller tasks should be unchecked. When TreeLine starts and prompts for the config file location, choose the program directory option.

    To use TreeLine's spell checker, an external program (aspell, ispell or hunspell) must be installed.

    macOS

    See MacPorts for a third-party port to macOS.

    TreeLine-3.2.1/docs/logo.png000066400000000000000000000070321506556630100156330ustar00rootroot00000000000000PNG  IHDR~P sRGBbKGD33` pHYs  tIME 9#0@tEXtCommentCreated with GIMPW uIDATx]-l\>;r R` fL"pZǠ* kPE5`dgAJ 2` >͋={O Is0 CgQCwq58ȷģA:A`1mu*ko.cU/!V-#-bhNsğ~e% ڏ!I]6䀯Ǵu}_ӊIe류 1T'8c*L|&ǃWGa'~ Ba[[O_ẼkXpBtORC/o#_'$im]!$X(={$'ۅ?As|ftsw`0ĹWG!=SzFe \SsrlZkumDUز_5C \岏]2_5)QIHqm#.xȇc6V4g6?{IMSH6E%P 'Kj#*`˚k@(#Ak%]-\;p?qm{*?  mMF,+h-.!po1Bp]" *΍ճ {@vKo#icdz_ەv -l'%.\ntNJxO׌#y/ ncRIy7טr)eZGߟ0j&J 9⏕ @\vO qű߮ğbŭbL#|PE׎~1űգ%+YGC_@vWLxp<C{Mb(r"xvoO%T7c6ɱXf9|"#Yo0m%l_Y|TإwEN M/Mʌd2w6-t<x5ig=ļNvh]ʪ} Hc_is]|], /M͘wrOM %lA}?JS7h1l}٪kyZJ5~3fgR?ֿ+8پZ̃ 5ؖ6v5Q!jf&'Jꈷɋ9Vn6c;S[!>Huj)͘-H9ɭ難!~)c6 ?R_+1[RvjU-gdsJt*?mqhVN+%Wv}]2},RuđjYo3,K^Ǿɦ`%-e]N5~3fou[wPҘUP*iЦ,voV&~'[e^#mc+#Mu|Pv`,lLeЗ(tU.Ix|4k׌O1r(RVc\Ke?lL5Yz2%u|}rt%&/N*3M {Kݠx{َYmE1mXG;9@vG<ȟgG1/_JJYOL9lcx#19Vc`e往5qhȫ( [6Jg a6rN4ĸ-ƣ"mC!\P=dVWΜ2/atbwzKľjZن[$.c&bӌ܊?wFxj̶;(b<[oQXBX-Gf)Rǵ=B@7)c;[<:gٸ.`sk5f<:k!qCl2%cQAY65EĔ㏝N" 5Xni0eeXStGY}9S3f>^i_hƯ!b)8s!&GL=aLWF~qvNtmk1f#QwQs֕%V ]o1DwzTg#)/ѯ[0ğ1[l;d;Ybͪ3u՜r݁y-R3f[(K漢_~lMj`"(vc+/U!~,,A^J͘ir)|{9x]ܲ>*SvbG.]ɘE*5կl[O] <_nCYW`0_2f[}Ie6 x^oRFEbe^p:LJe!:7T?s.e&} =P6L-o ZrǺ}.__wr]29@F0`z388j`0S7+IENDB`TreeLine-3.2.1/docs/require.html000066400000000000000000000061131506556630100165260ustar00rootroot00000000000000 TreeLine - Requirements
    TreeLine

    Legal Issues

    TreeLine is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either Version 2 of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. See the LICENSE file provided with this program for more information.

    System Requirements

    Linux

      The stable version of TreeLine (3.0.x) requires the following libraries and programs:
    • Python (Version 3.9 or higher)
    • Qt (Version 6.4 or higher)
    • PyQt (Version 6.4 or higher)
    • If spell checking capability is desired, either the aspell, ispell or hunspell are required

    The above versions of Qt and PyQt are recommended to minimize bugs. Somewhat older versions of Qt and PyQt are still mostly functional. To install with older libraries, use the "-x" option to skip dependency checking.

    Windows

    Should run on any computer running Windows 10 or 11.

    If spell checking capability is desired, an external program is required. Either aspell, ispell or hunspell must be installed.

    macOS

    Due to a lack of Macs for testing, TreeLine on macOS is not formally supported.

    There is a third-party port available on MacPorts.

    TreeLine-3.2.1/docs/scrnsht.html000066400000000000000000000031411506556630100165340ustar00rootroot00000000000000 TreeLine - Screenshots
    TreeLine

    TreeLine Screenshots

    With data output in the right view



    With data editor in the right view

    TreeLine-3.2.1/docs/treeline.png000066400000000000000000001070331506556630100165040ustar00rootroot00000000000000PNG  IHDRvPLTE   )( $  #2"$*"$"%0 +<&(&*9'-3#.=,-+2O:#.*3>@?(4D131 06=4796/:J*.>A3>N59?@>;AH7BR,?"B;FV@HOFHE3P/Yo@/0DMYNPM)\WJS_MT[2b5TVSIKNXe"c>`9j:[]Z+fGIX`m~T][ah0oa_a^/qQC`~ceb\\cK<|9bkwDzDfc.|lnk<~i3{Urmutvspp&ʓtb=20MM{}z,z3$MwP{{@A*vulAIf1v"^[?딖yDg]ŘqAruqg̙ٞKzE$ዱ`֛Ҩmv驫q[٬aůѲy;%ĔaXԳʞQyDĺÿÏLѪp͖ȳ֞s̭ߛٸѿ{ޘXٱ{܂tRNS@fbKGDH pHYsuucQ2tIMEѥtEXtCommentCreated with GIMPW IDATx [Wy[mzdU%Jdj WjQq #EXPG i#(76uM@IЩ]Tl(5TTcB:3J2|kښg~'\r-s i.\JOʪL=}z_1Sc/́\w^x3 uSk=?e ?vA\Ld 7y3σ֧<I-]pE;upP&VsՇ40 Oss"Q?;w9ghhǮr@@wÝ;Nî0a^<{z0nv`":e;r>ooK> ۾}LkO#G>Ԙ@l}`c\ytz~zb]|N=6yfmC5{ OYTOO{{śe;rܵ!ګZ=8]G98`k|UN+k__wү> >7G' BShQʕ+{sT뮽{|{u=t*qvlG'>{aΑF-w<6wDή 6?z㟻x872B=C޶}%h` M Mi4}bC'N5 jASi~<6B>ȓu!4?0q8} -T9GY0fިêOMLt_Caa!ONztG8o_>·˦ܫ5V|tZكW"2[_r}/0C' Gv .}ÄNk?^9M>,C;( ;!y]ϢGQ&N&׆Wvl?h j;^ sv$Q;Kuh}mC~Jȇ=u܊wr&tlG'&7WYgoR#&̞SSêɽZaG5#_+?g͝We߿О3Zr8'\{tuǮE91ڝïѷœ=P>vxֆ׌ɿGAyXN(B& Ahሢ%&12+ҠJfE|~&ǏI`$Q9ߗkxphxxjCTԭАC{v*&_ rߠ^kv <ڇoy-|e ?EG'\) k4zxh=CXcZgdy]0TRj0h mѵv7hP.G;wd0kz"'Ovp0yV&kt'D~'#4.?8%Jf`қw@"aPaSB;j(rU}k?Ⱦ}( VŁaTx/s.x՘]ydy]Jw̷CSp 5-Ql@wsjdd'TKT} o޾};=LҜK'?>4Y.y+K-o既%L؎'ܼwWNC7c?MP/ cͺ35B7jOyYNō#c3[n[7xB˘AnN]'?7~d]07oqm:z4<5Җ7omhUg܈VVNء7.n\rN&PoمgsB8K۷mGXl_kٵ Ԅ_e_Vk\ |.|.\8\ (yVD-\&ˆZ%F+^i~7eɷ@R܇2x-'Jj3ȇ͊#[oD*I"K$_:7.lXO/pj%"Ha<5| &?\. *;Td{p!?R,ɯMqK!_>D~̌۹}K8)R1+J|9ډDgNR-_v%mQ_UFsȯFo| PMZ#%&r,FL6fin!^˭<>%m[_)`gF|>ɢyTZmVH+NFM*B8Ꮕ̄rvDpَz P-/V{O ތ90bV8F)] ٫煱J@[?,mZԒ+PVfL5%5̙{M%L+XWZyZɉ##TDJeK1 G)OC^̘M=!`ɉ[ 5V+c(&Pz|zfJ+8wcǔ^*hbtB. jb1Q{JT3όYPdxC5zC=w E5kur<o .ȽySBN%:2]5{f %q{--VHw(0mC)p[9J~(/0GLV4T|>?Scm_Z Wd>_X`( JK秜H??B?0&1"]a<>2c]`fCE`䅂4x?nR,%cѐȇu,?Qc;2["3cȳ3C70k% +'j*t>(,|1Å?-j cF}:iL(Rאu:ɠ4D\\mj[@F4u>|ڡgwK ͩl7S\-&A L~-.Jv~vH6|gVH\/~'?jJv~ZZ(VZG"[ ?i ZIf0|F5Kَ"v!Gc;1`tOg`GdbFMdl ` d.L~ -.\G7pss¥$JtI*/W¥?@%ԒjL.b9{U:sdt7=8&nvJHTy]x/uM=NckpL}Kξu'N} XO b>_/}FW:0$d/gNL!e3Q<{ҹs:ݮ^ͯɹ꺡^83Bvl2+JtG?pUN:5}jjyZO {ıgN:OאSʝHgyKä3t>}}g=賏VSӳ SWNޙYWWǿx^s2y Kv2jFl/ODp٬όNjK?I*'׀|GΝ=yl3< r˗OT{\K%$ɤ<:'O\#|r i2T&JקX??U,NtѐJǓx:]c?jd>άé_W.v`>9W!?):ԱcO=:qԷ,Y _ Ի%&+ZTU1!(43O'zX;k_~' /_~Dl5 q]KO;wqɓǴ&) )]M3z9,V@fsɟ=5"g8}zZK~:"2 ~E^j~fokg!X,?IB} >G>-^|G؀æÇUF͏^|X:y陜dP!ÿR:R ldZ4WP:_!i?qyvX_!ptLg~|ҥ3ZsS-ѩBD X"͓Dq!򧦧9m/kc9C/Ţg"8?"'}1:ɫ Ȣ&}>|Ox>|O]O{o "Kw⋺gn txx&XdLWPVv>H5?&<?)= z~&;ɱx,2.O. ?8~gN=VWTΞ={n vJ7|\ L'zK hȟ=q̙NOhEcX,<_[-ccb}cSw=6Y .&yFy;ײc&rX|yVעMO$J#B~a߈C@^(cSx Z;U}?ѷv~W[D:GS@/iL_~}j}@I~wÙzZ?0퓵nk'66|:h{ky<3AN׮U5O_hVavgE~:#~/{穀cǎ _ǎEtNt1ǣX4QKFгW|;zs7/hg'^K@GȣxP!JO%NL#JW/xo ywEP~5tdɞ/w~JwuMwxw_WA1HEa=)zO>yܙ^z bL*+it*Oӟ|XHo򘗉ɣz,4 l~T~gcw~NxBCLc /IM>,|tG߇?'$ߊKvE"ʿ~O?!W1_~ : *//@LG}T|eמNN mzB)>9F7t*BئLL*&3&gt_=Nbw'#;/N=y2LF ]asCrdOÑD\9@_b/` g:}AzsUI z 3=Ϟ?C_׿O|u"lsscK9OON4OfO5dQ=cyWw_MLZ L&KcF_];a"I0;}zj; O&~=W|ŋ .NKiN__ZT*UGR+WG5D>2v0??}翫 ?I٫''=܏uvp??ɌOtAAB_ OVzp''C~Hf$յԟ^:_cLxʇ@P{R1:}&3׋׮NO.ΗFSu'os]+>C\%Xx~ޟ;ӐMzЕ) :*k[ddfl'XB%W7ON'%Xc; Tc2 &ǦWjԮ,]ʊ#Gs`+/<23r=w/&~|꾗8>?YѝOtTZsZ#zέL&W&׌^^+{-p+\V[y]$tSV|.\Ozd<>^q<&-. <,.|.\K$.#< ΟD\ pp9\8\pps…υ ' N>.[X]uٌBN>!{m8 i|S+Dr7=s *o],gOȿ^~?5 ɛ^ }~$56FC_xNJs7wo2<ض9dw\{nWOF˻q؆?lݺm7}62<4޿fC4(-E[Zj 84 vfĈOBul!W$8D{v?w۾oǷ]kԵoo{v|rnWKoznt׮90}zAݟb[6@^ IDATCAX&^nnj 4EZΐ Y*8K7㢻R4fU-(@ 68DOdX6-{D0m=~YF`pF:vRG]upߠwmzn7?,QOkLBvT1dQޘjI=C!Eb?P]AA/cv}j۵^>lڸqb6wle-pM_ i۾nvڶo\ky tfҨGl14A{-$r&6 \~bSj! 򄐕_ԭ<}Jt#i |_=:J7t3/ʱ 5͢DI0b}_u53YS1Pk?uvw`M5nI{0ýGkca+{f @|<./ ?QA9v#04s& hҔAw8VHZ.}Qˈ \|0$x 櫝/KÍ ?ĎBc;dp]cݺ!c;f>McoD[]#X;+`22jɯb2vps…υ ' N>.|.\8\pps…υ ' N>.O>.Y-rYI5pA ?.|.\x |\6Q%I -fQ%\6pE> ?6pWD>?/=W?O^姇?P}pïs[Deɿn,ox 7NAtNe) -1`''w_DZ$k2jdYͦTm5Bi1Io_8wcϚ cyI(-FOȰ!?kIz$[|>ߚҥocou3Y"(a.4n4+":6Y=^/ͻ?^|4 "FCeC-2Y  ?qM.'3J9!Q|"l_h=N,& ox7p%#e{}DW:?e[clɔ`[F&U2rȿ^ "j ͢˥"jfaBE!I-h=-HoG&_cQlgzQ! Xqcc89F>:(dUG-[Vf>.v&#KvJ0G$V|zƴtW=ƨRqJuF9G>ׁϽT^Pcl:KW=ƨ*Ecۜ. 5~7|.hN"_c1KzJY=Ƭɞ'׭ бzJz6O4'υs*t'p_fV \oese7=\(=b8׽]|X-d߂nqG]7Q"czZexVbQ)|M]]>J&vkƅG1 !/+mJtX7ZeA(,7<~TH#!ԶZ)A&_ն[i1 זb[+Q\Y!T1QQl[3(nȑYKQfl#6_r : /QH!ۢKE[7< zXZ`F1frFY[[9kvvɩ\fkmN%EV\$vq7+=QotFǴjϚal6cZLceJ#A^~Sq f'?b%SǒI:;({Čy)}aLȟtD؋Xp3Ji 2WByM Jg{zzZ·o(@Y|(N얬:͐})ɼ cf֒y(V,u qY,b:5sRo?F,3"A*HH.A>{L<VqTS'V0N?JIv~ylG *oqlzQ5N>' 'e Dڜ|.C~\^"$ Y< v(-JPDGM-랔c`I~ڔd[.e6ߐɏJ {MILq8]G~/ȿ6ğ'g07oU74Q^ $󊨬4Y@>P]l`'0mqc+n ݿ7)T$ aJZȧIQYqc b (ep-2rۿȌOw;>%?kl}eNTˏb{(JDq(.60k=v /rBZB(,X|d^U)J[5@Fq(=707x2jV a/BEgI;QY!d |ȧQꈣ Z|(XK.[}wUʵZ51(>۱*;&WDeكr9)T# i p. ~7+xϧc;(`uhX;RHP=vWȧQʺ:䫥9MWo K͚l3wI9 %SA,'˖ 312ho^s9|N>'c &e@_zLjql0ˈҩ%2d8\6ˈɚI['K6"bknKujkXQ,BkV6s8Uwz4Y2>w˘Y3(ij66gv5QRAYԐϥ%&"O. ߉-dN"7フFr+&+\r5Y|r1T1J,Palsꮩq=܅b&"L&!̀fU͙V{r8|.Ic,J~ِ,AhVU |t%&ҭׯ,粑wI,B6"K"?L !ǀfUvWgGD,W_GLN>'K粅s9|N>' 'e1Y\Aiedu'6|.X#&+撟o,B!NI'bd0:58\dIfŎ~%g%Η-Z5#FaD#v k [rXPsY_ja5u4’F e iL%x7Z EJD;?#ug?=5#68\|v4&RV#K|@|J~o/ˋɢФ!ҔAO aF#?B?sY_d,jDL>ilBY]v<ۡ?s>U"#b|%OxU"{L֬89v}B>_-WB/:9 I>WZ07|@sA-FL(r7QՐC-("ro)z)IHo+' !XB]1;Ѭ0ފD7(Q0nv*&o94wl NrE-<˫WquP׋Q7f9W\w^s-E>j'/I ? 4>!W yvq͝8rx tnCN5氝_88:z:_u!3. ߻id)<+bJ;3iY$yfpqeڏUMMw;̥ '.#{˙gϹpȽ'3'.]84u.C?mkp&o>(|!`ȡC'{pCdA t>Lȿtn㇎H}qpCܻIu;eAKLW$}2g` |S ݑ3`-psYc}[|IyT>A`\>_:rrΙK'I.&C{e=||܇t6o."ƺJĥ 'N_ {I?rgO8sSev:tȡ#1O8t8С#؎?sXґø#pЉpEs\8#5pYgh'ӉOF^[7[| W*bPX |Sn" !'N"'g 3g Lr rF9X %Nk| f4ڨac2<-PdݒG,$W!7bRl;FgIq7_RYU%u3Oڒ,9V: TJZ~]E@Q鈳McCƑ y*[iv.dl %Y'?͠hY]-9 X+mfw73Fv`'6M|мq#pP^ʨ昑/|zl`Mu>VȎTP X]eGܡyMAl,\|Y'?Y=U@Uǯ;#: Hr `ս}gjJ }ZίMܡWG-[fc;'Ǭ9;bؒ2mǁ\#&_ύ8ضżL~}dHc;ΰ7lTspbpPLNWĘ,4T/K:n*]s_e0ȯGT%u::%<% 'ȔV= Z| _ieu^LE-S@~j5e+L>"IjD\ci G]Wh2JN>rL֤P1ic #ȼ0ԉK&_J5l;H4ny<-j$8\B3D1DELo1ԉK&jR"?]w01k-'=\.B~,s+h!d &edwv~*/O8e#_4&%'k0XĂ}ҥd|.Ob1Y'҉ίR;;q鐏}lyr [K,%'HLS4qvFۑtǾX||6J$6KmXՉ)ډ( #Pe% Ml ҳF_}M߼6Ɋ#6,e$VPH#[ҭ%od : n-ݔ6EScJ#B"`+tw;ǐfk7)m8Ni)KMz 1JO+twY;ovopNdIF,e6 Q$V)TP`绣!@4K>Ș[QM%+܆1YJ#.dRfch넉_h6mOSJ(Ih8,!?E䚓m8pΩRfchkkd<>Jvƴ 2?k.3Pfn]E~+hl#dm8}ήh9z  m8NR>qCZpyEe,I˲f9|N>B!S0Ԡb nV3}k}h#2n8)*J'kUn%\LG=f.YI"pG&BB6ǩZowWgqhK#bJM`GU36}.Y|FF{ n-\Uެ\r_]}M>v*H "Fn Hif|p!2.Ebqؖ&2{$?I^ bӐh:, 4s䯌U-mshR|>t$qNX4䃝_9 }Ytu[A>KKg2_" pW{d,؂{VJHkK^Y7f[~:9vAF}Tc;bL 4LB5 KcC]{ϒْ|E=B>|\G85)u3[/*E.Ynw]ZU(x]M~)L~kRY.ǝ߀CA4[A>Kfcc;Jۡ'tB ߝtψ@^  ⪈1jzlE8uɒV_ibV]* Hc;2A :qUmA\qzRTks7kLyzW4_:emysB]9\-|8|N>NcpPLNWu\/;'tvu!鹟_#u#ɹ8MU' m1#Fd2TuRC"[us?S':*Ɋa-g}s~Zw㮕$@A+[k\'`8RO+!pm\ v̒Yh-4tu~wuOk\)5'drUKbö\"KڶG[DݨX*dOo`L*ɢ-viUJglƤ+ɚ!Z;QEל!CbgTő:Ycg?TShN~?uh 9*hwEKRI=bTClƸ+ɚE~^"wT#?nMSD=fiY؜E:Y+h7Mm"w)Z#ay;;#v&{ ¥:YkN>B턐&l"gMѐ/x8E͠h/=XNuWuց|+sʲh15E3"wG CG/筋x2d3Ӭ) %}d种)9/ZW <&ˀ:Y^o '1Y̹k BK#G s9jAԹk{H2%?$ߖA>EXX.ZeKL,4]>JT{1W#kMɯkfnH_|V Ԃ{6JQIkraQIc]aUhhVj põrȏ*JYhH qRw[pcDR*t=mq*g=P¢V`QhhVtSqUe 1\b1\kB> .)@zaMcהg |<.p3"4fFPfU.\1YHrbaQ\:+'qd?%S*ڋpe\X(kȷ%=ah7lvȧE` %,YB:+vyҟɒ.wEittxT1\XA`5#l4z*G`(-4 P̊mC*knc@9]# d]RXԤ Vݶ%@kbYL.õ:A{ίA4c̵;lO͈ K_@LsbaQ1ۡYy=Y0+aszQ5o^i;PQeG3$b֐|\Nzp1:^ٴǚmT(T jK$JB ((u.ǣ| B ( t3/sT#pP^]ϲ/ton~; ?#?(\,.I>2MYaA3ekq4C$'+b<^UA+ϯ ^)X?l U$1ֳ@S1[8 ':GL̂-d}wu #bJ?iGkFkaj ڸ7zmb'[]_8Ȕ͙饮#iΖ1T& š$ɵ$#3|)bFD]^[' 6Α-KMf,lg dm4$4]O$|&n$-FOEO /OssVEF#Zҹ'/4>vZ H!F#\F>._[L8C(sAⵉӬi|Y5A(/6%msher^|ͼ1|4 , '![ˮu=/6 ,d5x%"K9423q˞@> kS'\$'T&|$y%ٛlUl8={d1= W4j,!)|$:خZD%kFg-)::y2+u>^*r|eg  |,39qu|v¬W^P#9wP_,6Q [ K|dSc[{CD˒ߢv>dfv>!kS%\LݢIH|EF<,dUl8ɪ\dl{v;W(QA9*uJ;6Xh].4ikɍYn*^%ˮuKM­G=\,~Y!?$&FC-+v$OfL<צJ!_c;Jifg:CVE},6=79MaqUE0y˨-5IM=[:בUxw,~ cq~N|~E""袌|ZYDKb߰1s DNCj,N&WȪH+Ne"]Jpӎ`K_i'QtsҐ 'bD'v:䓖W Ґ/EIEڲvW 'Kd"97np@b־ʭM:=/lf/&k*,`t\2\K#GƵ *Fd-rB[.e-|Nf ?Pmg2[^.;kKהckGJ|18[-ձv.>WdwȷTP`TN>\H#!IwR\ьD,1pC~U&eYDe?XuKFfLo,pk2,e.{eԘ,mr {@dPB?C>K>8EB"E_W0JjO[!%vQy]r\NVQ,/-,f3g5ȯ́ϒG.{\2Uu|Oȧ50Qk]'FP"7Ì*1/LrI,ƐυΗmEaOka{]mVJ#|CbRI,X|N|0!Y;0AWY>M09֭! ژ.N>#wL  <~_i'tAR2 tmql( dp Ok͈SJʚg}2 4a:7N>' deAc51łڶ*R;?<^ią rFPQ쐟0ς֟ 9aNB1Y8<`c50ic]D~! Dhnvȗ|_7XlI9C+6I&8Zjs*knySUeX$EnLwW")^[-F#P.ҴH=䛒pإjDjJgΐZgLy,7P``Nx͢5!wNN41HCf3E~. *vKYcURl;KɁ#0!gVM"X+Pc=drD{7}Vtu R1(S:E%xLvvpTײ"4L_[hDX]+ЌKpfי|{Wab:㺯a##ks`/WBcL99˄zd_BLV|u-+Dg: & XGtȵ薏{U[ZP\h_%sT _Uˊ0)WN"䳺Z+FAח|-~k2\ Ňs9Rl~B~8Cɇ?B1#uGeIºfcXN*^,8D㨔-FOKFw&CGD3L FX1$n`EL&XQ#D _UJۡi+'Ih]-h)@>~k2\ȏ1cC@>͹+)iQOa' 6+BM]iaFV(+tCt~\hx6a"y.Qg?҈Xgvgt> Vo (#Nc66o>o*!b )Ƞfeiͨ\|7Н8莠I+ \O)'nfToY;؇l-9 ;Fyg;䳃c eR[!MLȇy$erլΐR7Tbcf0g9YF=e ZM6J87|uWA5BO!/ Ado1g?҈(|if|vp|6 Gfᙜ=JLd0ɐ" Au['tFP@Mcٺ+z)!?kIQg?҈[al:?'e}}ydjϺߚ )>jIIy;\VjGq-e[@Ul.N}uluW&*('T\]lf^ߙlg;䳃d@BE1S;H]p>ɐR󌸂`l}좗H9W f.cAe8*[o"=~R;DvjB׳LЉڡ;ۡȧ*N`+^@(&k]$tܱ; o+c6I('dmBm%R:YҸ^9-Wk%jn1ݵ1Y7 BO XC~.B|Nu&2nseF=ɗ+`o6fohLV<%9gIs,]d*s&KNUgm[NYX6 +Es7&Ŝ%9gw*PevVFG - vAeu%ȗ jUP_'2Idrw2uR$I&CyRҶ- ȯ 3(eŲPRO j]3'T{da*GUƢYJK̡ NR[|=r,mJ|u9Sq9K$wLVȂq.Ne,M>sR/enQq{VR'T]T|NUXe,E>sROR(L~w>{A߿iIEGap( @(  f%a0A`!4=yΜ/./3bh),a:g:%bXh@Ԋb*$ɿ,Xz JLƒY;˂*|(bY SaYetb*$ɿdp䟱V IDAThА$BC_sC|$ & GM˒ ,(o>5eɿHmmubU m Ln2Svˢ;IXKgBM]ufJr7W7~Ѩ- (6e:m]ٕu!;+<3zZ=Ꮣ7/Q笏XUB')f_-FN{jl=(KodE/mo}ü?AШL: 2[֔^/e`j)NGIl=pW{mKy{v6g nĿiRƛq#?& ɇ~;,&Ϗ3rޑlU+LgNFZ+bCk|>D?f,iCy>/RjrqK|~lN `J{m yV||Jm|mǎ.`n &Eh G9BgYz}I?S*V;aA@N  TVg|)zr0bY DU!gf JjK=Ѓf'0dq~(Qfg8YvʕՖjCXhDAM LwD2xֶ>h|)p^R^oX|]3D%_vǖCIe?o3I6ibї!}d07XKf%Yg}W#/DV.ף|%I#]x33ʹ:+}| Ikfn.W4or."g |!2ڟLEKc Ոv6-M9_S| \"t!""+ -Y;q>lc});B}%K;\UvԾ栛D|э[QޒI{YqNӋ6DF;i虣lKt̬|fSB5ؼm-p}!#Ta Oر[b|Μ&GM& E G|R<̩&޷3BRSE9 hWV6w)5QZ @{ȗnwo+X1˹67u7`5y_bUpZ;c')oGzoh/.y1uJ}|! 2 |)JL@S)#|~;-4S;06arr,}jUz^#FH>z67D+e÷1`$Jռ KʺI u^R'^+'X ׉8_DaWC|HaOfF(I~XGLE&D*}D pҬN>ؠ(6)RWP*O>,SCq~-[ tC,Vm}H虎d_";Ð|¥qQU7=gqV k)f}+&6(+]aCɗc1,$VqO tm;䯭ig̀,S"Gz:H\*D(|%5 yR݌vdAWڍclׅ,Y]lPW4P^,|O|)# %V;q>B>LR8Ap/_!EaM[DCS->%AQ\)6O|)C>1HN>s T"& r;\! 55ۡ+3ioPW81ŕA꧐/%V|k..>5H|O"& |Hc BJ@(DnYP!R\ Wjn'"_J$=ygb&B{AQuI[^{'/mcMz[%?/7BMg{umfu7$};hݗm%H+cCız6}90[ 6V_G~jze|4>vP3f*եkJ. "fӲ4 *ySRAg_vnJUJClYM#7RVK,G.վ;ԝ+ˢYŇ`ه^Nj@D" E15"x˯E i$zׯ?'%s6ly+- Q$? FƐwҥwL ׵Clim*ۉ;-ӰlC˫y$+ʢl;N^T d~_KJ,(0=w k?=OvD;}6?P;R}ʯ|'[QKvy /ٗW,Qv^, +>d)'_.D}˯Fhxb:P`Yc|+!} mx8Ul&%bKjly6 a1%_m}yc0O(bڎpkE uoY ߃*'_#wd|tN_?%-V2ڱgz{D[e1󕾼Ie^A\%O/KA8GP[c˷z>&>Tj-;}Ǟ";V0K/f$#U+=k2A wʞM蹩O2gƌti/[S+"gEej_$O,f#$^'@ŠY AK|_S$?&X,O_-F8K%rmiϧ_IEuo[)Vh2lSS|?Gdi=0jiT].f݅&Dg$ _e!hk h6f%* U8gCEٰ^S>h8lB竚,! }d_%!O?Z˾Hێ:V/Z)llN>H>]2MMۇ>Fj_N!$)bٰB% 7tW?Kw[}e3,kXl*$+e_%!~c:43 +tYkmE_# 7ɿղl6gdI(Q"e_%!'}:.VΆю|뮮"e)nٌ!5Y"g&Ո|WIȫq~H2V0!Z uWבUV+^nInٌ%4Y."t/*IyN!#•ٰB%r;7tW$VvF~JǞ Ol7]$[M|~)ڹ]![@ʱ$ҖhDi>#molOZn_ [6 +fٞhRht>ײW.ۓV: s;glFC+;V<'TglF&j~nвGM߆|d!/JfW]{oOzdA6ɉCy8AXH>Q>GtZ{՚'cO~=,0@OhQV#mŒ+~ fۋG˺h9cm('˗d5Y̮u6k+Ͳ6F%Ym]68= 9,t/?ϗ]~GD[rz]l{h,ΓnY*ߝu6-FH;'>*̡BsKO?՞O] R>qPË]6g[89>uœ}iWgw2C8FfV9@~xӡD/M7GlXuTLzkȊMn|?𹙪=F_ZW$*BaxȏfGw|,Owwf$=dɷi3}wRĪ=7;4Gby)V_H}k4n?Z|> g؈TIO:|cD`)#[-mCzi]gws嫸0S25FXY/SN?jQ].Ͷr;4I(w#MƪBwE|_e+@]:0>o"䖰alk3VjhS~XHmXѐ|M3ɇ"k_h#Z։8_Dj)j^[.W&jd/|n*MJ{jH /uۀL9$bևddvYGl,q_/V|pJq>(c%edig̀,Sk?GzРm3tWU4ח,_ ep@ނ]ǰJ9Y_ýd`c>OZ==GMK,%5Y޳XzsNYkc}5!W9<2:.4ˀ=? ]9$A'[coS瓿6ѲOg eJ#3N;qwnJlfV !'Fo'ݠy툞I5M>O_f/TӰ&ؼT.o$d }/%4| _Ҕg67?R\Ni }NQM9+zS&آd2'w ʩ~|4ݰ:$wC憈vң|3s(zVϭ7R( `s8%N>)sX,&vnG."ײwIV?5YԂ>`^Ʋ5!W^|%;Rh',ڑ>ߤrH>1lt Fw|B~P#@aMDž%Yhao>W]Iкc&פGW*d͒qjCz;?38\VJ0<:4YMG2\%wɎZwLЌnU=2NQbsY!_ÓDu K Z _T.يBGC_ɺH>>Wk|G$zM?#H>7AM ,%5Yh/J9J\1 fQNske!H>&+j.i&\ァȿٸ,$ɿ')yQN>m/M'zu/"f㲐|$r  ;mY-Sȑ|QF;U#M &eO\#@n3. GLV5056c EȒ>_ ߤOL=p V+e!H5>;gT ,AZvhBWìbmw me!Hd&5j%N>QY;>_IYnTkn3. G$&+P+M|#;#$Qϟ &e ĺ͸,$?Ú,7(_&URY^s;Uᓲ]%gn<. G/@<LNSYX>>ALʒw!SX7#s aK[B9Y%y}ڹb#B/jE|&\?&Iϐ{$?eܳ/mOtIkH>6dY4t#3 y#yǥTXfIToiJYͶ'vVM|$>!MVMngH1"%{Ije(z|S9$8~] )*&鮑;#4YM97KBAU&#[i.e͐|#\oMT!ҞghwJiMnOd2vuN$?E6NX0"=C5:ۓ|Y!M)ɺX.`;+4'&_&|>z"Bvo:6"Ϙ'}>>7Mձ8 l܉la6u0 Y?p LDz*5Fό8_gl#_s ʔ7ߴd-#_]RKogt%Á&-SҹFD>:*vD}LvD9(>|zK%iwH b%)~GDI:wr.Hך7ϛQeYyȏObx&Od6ӣӓA{EZPߟ0!0鱦֯pѐc,וbW! G,uhDX,_|: lAr |2ot&1$4Yoc>,uhD/+C=ۑsCB&pnq "a:H/}Jn'F :*$ɢÚK\@dg$ ?ENM5H?&s'rC^Uh*+h2n_?&ȷixūEZ|- AR"Ī;"GzǞ{$[,5A}[3O(hd^!{sSɇp_έ!ѴCs\z~xQ#25F@Y,p@|>l=?P"Xv[~/BiN&ZL&5 m(.q俐& |q>[l''3^[0F#I~I< (Ik_IxU2ET&N{t5dYtbėvj6fąb}AXȀS `:俌&km')ABGzP69Cv dt0%awO,_(eDMl:U"aV&xߥmnwMv ?IDAT.*5|aM们!uu1 NjB>GeW4Obp پWLn#=dq}>M.yDx6Kh#veUq3FKSaM!hcVe)JDGh&gwo|bYMMc˾M-i}UXuSN*i+I5ږaGc#?i& %_OAvSJ/{x1b}qhA*ƻz9ɎP7YឲS,ynk>I/6Aq(MVbiٺif,`IE';т$${ N?ɢ&.>?O_C2qX7ɥc䷶ǗI`Z=$Mvw~c8?/·M C|Ѻ64Cuu[CE_ՇQ҅oM<[wvS-3zxiXf+.i75?N(o8uSK ]>eG/H:4fr5|ms}>%_,l44=>iƩqM !{v/29zޭnПj{Wyo,˰iJݎoM:e|sU.^ vYFzdY#}Aױ!r̠KO_BB| ϓ9]eӔ\b/[Sl!nVoz?i$ȗMSYPI-9d% qm1俐& Quכ>0/7' .;'k׾;~yE;$9nwd#$go_h ?Bw&hW#9#U|&aK1i{vb*TtG:>~?C|YֱgB|'7m6|$/4Yog N {0(Kp$߅. _NHu;'5Yr {ȋB=8_)&G{XCMʆtc|n9G;ې/ϕ|uj= ^69{$ݐJ<pw~hN֩c|9wb{=-m_H_oO5'GGjoZV͎Adlf@wBc?GrDNH>R G_ ན_,y䗼5sH#'d="?Jf+$V_.Abx/?vC!Ǯ>&UM3e=C u??wAy,N~c1n[sj5fg>7ASiN_\zuRf5HW"SV59 J,کh)q$1;[F~52]| BϪZ?ve[v;Bg_ަVw/!g󗹪\юSښAm7R -HX3Tx|^e7>D;|mj5+cKȧ>=gYF/ns?dʷȯt/v>ZCͨyĦMioO_ +6>gڎrTiKq[v&8nN}M.jVPOJ~ɗo"7v+k(fhO@:3!!mI>|vd3S/mج.g8v>?-z:ggI/\,8C8%mۉC=>n!0|8F+v܎,&zH֮K8c4[\Hi@ 拜e 7,fNϒC=%/?I>糾66m'dwrzʗ "q ?K>$"SNBv =oʮ'C|FL!`v-[F~Wo_;ғ7eדO`?B)5i\ f{̓ٵGoV\G9=_GFO~(veɰ;Nnt#?F !׵{~ ȟȟ_e'!L-5 GCCА|44$ GCCА|44$ GCC~$ma䣽Lk:a䣽Nk:a䣽Nk:aj!hhE?4WEC{=J-_KIENDB`TreeLine-3.2.1/docs/treeline_ed.png000066400000000000000000001027571506556630100171640ustar00rootroot00000000000000PNG  IHDRx1PLTE   -( $  #2$*"$"%0 +<$&(&*9$'-3#.=,.+2O9*3>@?(4D131 06=7796/:J>A3>N-22;;AH?A>7BR+K';FV@HOXFHERro@(Hɤ/0DMYNPMCE)\W3]2JS_MT[=\9UWTNXe6e7NOR_T#r%[]Z^\_?cGI lX`m^`]B^[ah0oa;_@= }饙ӧB'jul_Oa/=}sz2ժ't/h,|ד׋{wm$]h/i^+r#L5ђ$2t$${Եgؖm{{8mzÞ[֗N|HغgnQ;b{vi]XgN,;{췷UОaw4i~۵kndһLYN{Pc:+/aiHžm[Lm|^v־hm=i7ܝu۠-&?fQ;={vс.fn 綝ή5+m;vN 8Qw!9-ONkm)$]2Ji!Pc?6/}ԫO<;3h[Pܹs;a:s vo͘;ol}{۶e|o;L ηv1ғur7Dq`wR2Hm;RLz}'ޡݰJ:ڹs?w췹#Naˑ4e]3zKO};oU"d o} OMӐt[F[7lA ƶp̛7o֦woyݓ-7SLXLOΡvo2Lq->N AqSK aז{ q,>9#%Ӈ]K`|d|wŴ[<<׳Ƶ9@%v1077vDS&v(4~}w`gvЕf)  @Ζ>C6Jvbe-׏mٹhY|سw޽{x'w`iG`1#h_W<Ȁ AѸe)mU=h?=}$ӳ_?_Omo+ 9{.l;F ItؘµGl{B :}=ضCc$ [4u!𜎡X$ǠdxROJ9[ň Fv+ 3qWI덹m||{`v89~LVrƎSB>>}Yu𶍏oJ~LWw14f[۱ՒL=hNӧ!׏m G5'״=hftµ? dm۝Aɱ]wlzwau >0x՘|f.=iH{' LZJuBln$o&_pLu8ٺh&Yܶ1L>>w}m`n7v!|*ƻ6u ߗ<ݿcɀ&Pc O~ZriHzt,sONC[Ta]'v5 0ɿf#=s0LGfd^36c}cFΘ5y^`k{Iz ׀|MOin‘N]ɿخajb̘.W `p!\^5&l,5C. A>Ig).yy$OZJ^fq3dZvC26c{OvRjUȌB#~]-'NwXw<~8q5L,ɯ?o<$樓-m|%ILr6uxcWo޺c R|ډ6$Ed˺ lJ^9/KIH،޹ykfb3ڦNt/ eȺҘqWh;r9NŕGfdnX䫯2ѡuLՠۑӧg?Iz ʕY`ذkK^i3硞q%.fXJ ZڢCЮ\~ Ԅ+A5?yٓ'? Ir6o[v3CkHk & FPz]8)T|**J>%ªj81JYUIZPa~bK'2a@ZjKEX|)YRYU2pf9oR1֨BSzHY} fyexUUqzGC*>QJe&?(J}Qc A$QγJE&_M;2.Cy1"p)4TXtj4OXXJ; ~m~f~SFW|A89j2-""&E]yLr|pprطiF{2`b1JxY!T_4SbWg7P=R>RG-r .; 7L4tr@~f]U%?YL{.KE4XTj n"䫢 x:_W=p1eVc`.>O'֨'+[EUB[#Q*#'v{K*.dZK]!c~vx4aAzY; +oS1 !E^6o'X% +U'IXl>D l>W~5߇pH9v2m~ioVbO~Om,!AW_YzJ~MAYeB>-j/bݾm̕UQk|5~|FﯨY njikԿ_~X;YkzwD [?i(ZU}<.ȯDX4Rpێ~fު~lPA KV3|Ջv¼Zێ6,i]v%hK_ x`5R}cG48RMcZIuJ>_03w 561|..LvV|QH%O k,3D-RVk=Z_n.Jɧ6OEW6,䷨6,/PQmQ(TT|*T Q;EFEioRQ \,.eOYN[C8I8kNYsW^RXo>3gkG=q|l >:uG.\ӧf|Zס!?a@CTF_r `I~L͟= O>ћwR)%h,jgϜYGw_+ޔj _:=- SF-sGN=v[oTUo|Ŏ|Lٓ'7C?"gP\>gIQr?RTT R7̃|p:6#πo3/lkU[կv>;QC>ϯ'?~1(/{g>,fs DF%'tY{L>?}CVG̟={HױWu*/?tgϞ"\4_?JqT*t,˂W+]O!JSD>(Kkl`gyk356s鷿ގ^W۶s0_ۿ*A埓7m<~r8wyvނt|_ B'_ Fs>}ĉӧgzjjb޵N'^h5_؋'~W>qϞlU^tƞG9r4a?\*؝R^qDRUn+r4=-_,N6k}u|KG͜?/ρ7{;!g㏐nڧs>Ů޽{<\x:{o 8=b!aQ^~_~1`COŸZ.eep?Y_Qo`ȏz?zO<٣G-H5ΑᔢhG~9s^ˇ''1s_PJؠfs,vOE/ÞuW<3Gic]0}O<?(a`8F~uW|ӟ3ots8V/ʝ7Mڒ{e;_' sw-Bgod$bU)ؐR~~kjo?ۿQd (3QV8ȅ\FLOXܟ?s╟ѓ=: ^ɓ(K *<1[8V)])T!6K)2YRŚGȯek|ݳ?w1 FΫ f->/k=>n-|'a8\qn==7}M/&l4nvkvo٠˂?_)`yȆ'}OtflF'[ ߭Ϟ͏,?O#^ka\R-|Co~AfffȗEy ~,DȆCۢ*f傘)JFzi5}ek#h4jj:~.2Ao ? _1kG>mI,Syr=ϩ}O=z衏ؐne &?k\,I1&o}'fgO=M'>~M9l&={R\^ordJ߂EKl6-kTovX sw[ov u{v~7 C3 ?𿆝d]G]ڽ*zWA[r:T3"ï,_fo0Js`yǛ|`#REMؑ}rppy:9r:V]L2PiY-+4b!fb!cr_F|w7?0g]ə'1Յs.?w[r5k`:+]zۻu{W5wdې?w܏uGfr"V^m{-5܃O9}ľܲdiJS{gswߵxȡԑ#v6!Kj}+a<9ӕXAFp}etl?c[}Qͦw(LʿK6fmu~Y'iC~Weߞ f>Am67ޱo߾;>ka,v3g $Էuj彝~Y,-;ffN9{,%Ҷ3Uȋ-ɓ_:2; }r)BXTU(d;ƭo_9~xY%ܷZf>ّߞ?{vv,Ft܄c3vg&%+UZMZ7jdC|x椾 <a]~cFEx 7;O=e%R*S~O~3:_t_?kfWg}nr?z |v7fi {kZ6_@|v6ۙow}Tnȑgݿ:g&ƲkJ̦mbC> X3||7m3Mn_d`d%NW2Hj \QʕsvY߽G{VBa"S{. }T;d u谙zNUR tG_KQ i[~żls3]IGM}xWfy5ۯ'Ol Gwޛu}cy)?[OpjD%MNI_Mm GY**J>R/PQmv6ͧ66(T|J>%OEEɧSQQ(TT|*F÷,.|kljQOwӦHUD$Jn9˲Ol 0 +NG-q U/nzxԍ]،ȥF1T#3m;Ŗ-ڢ0llI"_o?ؾiTq e훮zm BĈCO[tM?v3{U76⍛6Yp/[ 6J4tX\˚sBΤEa6ȟS50ퟜ[nG5bK|ގ?<#LjfЇn<{j'-1͔A~¯4C1qPFgfUZ5o ,P68xH IDATozwlMCoDtg`ƟVl4"w)F}nvc3ɳ8ȣp%*N+W42A ?OQm;g7xY 9uЇq--M-n|ILeJ/^_}~UWm?,f3x/n26_p3W&r|ۛEH'YJ%8क^J>qu^f?Iwc~V'`l~fLol`ө mfĭx-Ό6QO}g?iykyH|$=] wj磳ca+߾n3轆7?  i)9t~=~~e$# nO~ xX-pcOQ<9=m}FҶs{[07~rf:m;x3۱ ngbK#Xw fZϺE3|JUA5F#o(T|/鵦ڈ%OEɧSQ(TT|**J>%OEEɧZSQmт@Tt<\UPGEj6{(TTt >sY5-ڪ9P-4FC#ME_|[_Y^jK"'>qOP|Ǜkxu'/ޕF~6KxAc%?Pq )1܉Yv} G'_W #'zr‚}_,jfz$S/Qڿ_y6FZU5'b=ԧ> Tpx\* _(\5J~6&͙r4UE?K*C3vI?f|,M)0`E E\?3g> BV NҎ_tQYP,nuE)1MKl|z:I@~Y"e/V)6U'H;ӊu-Pڇvr}kǏ<]w+~sjaegJ[\it.]ERdL~R"ɯ%\.F6wVԺ/TU*`Z Aϒ&iov(ҷ.{o&͚W\񉮌燣}6Iz0/ ,<9Rcbu3Kp;,|'GUBj{ V0-Q/U+sEUSNT@7əBa|ŝDR^wC&puZ9;+J+i|6_vj(%T+ϦW2\Ț N E~ɺկ_u.qFEvzێDvj;_*Zd!_Xc1:%^`l>S4B*R/|«7 A6_*pk96O~F[u_V je,)%* Q+J\`N֞zR !_7(f{+mf<@O_ GC%Lh+ٺP)|/LJd 3%#z;T|J>ժb.? ke_bV}^V|X-^MEɧbGlɾnQ)#HбZ@>B)/BGh9 M@ unU;CW ss4%?*6X-L~B(WLjjkoj{'5} %?2ΰZ=q/2| $eHZM?UY \@|Z%!cKN 5J%8|(ț6w$Bag`%?5\X-vkDM!C?eT(@BuJ>%[5mbM~jyw??[`m4%ߖ|b|ɷ"䣄x}C/حNN+TZ'.|KˍbHknS/'"Vk1򵞦tgpޯNtEJg Co4c~xQj*] d ȜϱÒ_b0?֔9q%=MW0 QVPZ)jr2퐎$DžW(J7;JwqQ 9C~ÑGa+,0i&P)KӔNfٴp$rŝTS̄Z;~ $ʔn]eZ;)6P-sSjQ'=n_W\YGuB4 |Jo4EFV]UYyhT5ގKD oBb9v^RO_}򍞦~>[gAf3Jhxh_a@c('ԄCIp\BONɡ|F"Q?_C30@l[͞@i/0!ߴ|OstE'_|kP:M{>[J 4CG }oNfi*|^{1~'iKXUKlO\c(s.!~-;(#B>g>|͠;ov{z_)9\ mdžsZiLc2]C#u.D~+VQJe ?ן}ݓݥ2a8_DLrdvZ^S/}.61co IتeɏnJ>}cm4C_|ɿwY"󔙒N fU`-L~B`=S2,}_`uGB%?^t]SDV;ev'EV#?Ei-f lb !\|Jpnn\4|x_'_¿㦷㒬QYr 皲DSH\uB(/}3>|sجvloks lUh˚?KA TbC(j̝o馛wYBLdT!\l>#*+86OFnW>OU]9Nn]J3Y+Zj(4P/;(,QY(yVx( b2E*pQ))a~OʵsSwZ/n|m]޶Io'=%6O %<4uÑ.+Eɧz:w0if^ӂ>w|JRP`)ʔ|ڗZKy9$:8OQ)vCɧS)|J~6FL%߫Eɧmn,GբS]fe3~I~)Q)k%dU(T#FbRވ,`@ꌪp*BΤׅNJ7geHS)̣C1Y '"$?lY |`5x9g`2x8-w-5f^*ng$9XeObDڌj-*rqwz|ᮁ'Q𲓟`P'_vD^SSzU. SGRܞ,|rXb1bkFvE-Eq!P7 ^v]\+_B/NV{4jd,p81VP٩y`̴A~%8ĥ|Ҷ "{'NrEpLȧjH,0yEQ&ƨZeۄJ W?G /k6֊lٮT E"BQ'Ie ObY)lPز1V9Ú͗xkDW8Q[2݈wpb{Π3c:I/"&kwϑQTȟ Nc.qjf?\u?:%de 4!%Oc(|Eߘ/eNTcj9˔|!bĀ|Pi*ZwC(Se3#O5/-&K ʳc~}sEU^W eXN"gÅa)1Fy#+(7 cy UɧžeE~aacdّo|T$A|U%i1YXXnu/8JHHy},xC~Fn,)DK1YXX|$YmG Y2ȟp᎑!mJ>e&rdEW'BJ>%xrLU)T@*d3|J%OɧS)|J~hLJ:Q&4&bN &(%蒿&98V'X\y/&gyxJZ䧕/M~~g\ yT>&k/gj#wV|*sqҭ8x;y9ȹ+ 9kRGcq'乀,8_]+ގr"},=Nȯfc:͕pVq{zvbt"蘬`$hYqܖjL9FX@>mŅXsod7t3is 醜?G~<Q(*35V$wIR URB~q}O>4MnȫHU9V03(&KDɠv=:tl$AFҼE8Ymgƪ| ,w.^&/x6r wј^#:c%s8X{<"V7GX*~j UIm|nUPcp̂c~EQd.gM>@!_Tsqҭ|Ҷ,}s1O ގvZ%u/%aȿ_?k)CkO>w>[C0nךggEh~v?%})/'1oFcݻ"C3v9{)TFzLo&NLv+g=1'?ګ%9}z;T#|&#r8 f{f=ٻDGgͬIPGc/|B~߳?~?|;q l a?YC:aRF7{D|MAl>13^?{̙p#.%mNM{>ZÎu=g3O_C=zĉC{5_k9O~>F %vx5h'=q7ﵶ >X'kv3|J%P|C< w'1UxW[|lQJ>%ݐ?U'nTI/ +C~kh[|~J_`B/Qa} "$H$RKB(.CZL 6̾MI,*9.i) VV )հp!e;u1pD]):g)|]kmw]d|&P(Wٷ3pbKKLla *2/Qe'OqRCUN>\gE&ᮦ!\ -ގ e# ~?vb~ݓb^ҘLc $J| &_A(%=U4%=4~ 8`"(RcoѸ$ee}ӵ`TRz̡Jʴ7]z9G;GR11CGUwSSf`弚On3;ƀ|܅o:d\̷MempOh}{p<#@|-fq*KN ekjڃ15rHŀG.\`#qw!A>Ҍa1z}6_C]$S|@h%_~yZ2RcXH1._pɩ NtHp^5ƮL:! cE. dd0'y-Z(?UϗQ-M5|'}RW#ۿ\~~O%*ðB2hF @Dֶѷ)!?G%ș6.䯠&_h5*QVpCsbKEȷ'8@ZY_: @RU|ގb}PZ0q[F] ͝l -B6F>\k/< 9ӽ@Cp<XW8P Ľ0p|~ -jU]WP)#hbU'?v54w V'1N~VPiKP=B+J3W?/IE[vqBgmyr?6H#,t54 $e } h~>JHŭPVh/LYB\W66B>f)Iͥmځ.x`O6[ۚg{jh6{2|<6/Tk> G~QRwCـM>A~/`d>U*j~~FnO70_,ܞ ] fv78Z(CY?ǼfNPSG]M@^Ӛ|J2F^%qG .#%1EɧSi_/t6bLՈdQ)4&O_Y/uGD/e SWb a ~/NV,PFd$>{!ps;J>Ո|`_ p 2B ']%@~ }Ftv2]Sod+&IJWFAܕztKmJjO&l>P_GcF/=I~:Zzt~?IkT#ܞXLV-0 }*$,Y@/SY^L貳iMQU0GчpteTkX#Ւn?6QC\Bd5}>#: /8JHR/Qž?Jr?0&ჵ/AZ&X@>#: n]S$(&4ML^5UҔv%WFP7S)|J>%9fئ/* {j8AfW }oNf1Ʊ=,—jg=7XOZUs+.jt7WT^[31joXpvġtͥFwIA~ZnUMq,x.PQb pKB 䋬kJ$zUNLҪ"EgU-W +>9rR}+@} $BjzZ]>߀|lδ,kcWU9ɧ Ӕx6_(~֯DYOEOӊfq`s1TkU,U:>գU'ٜa]&<Y'~vSbWJMVsJgpRM G^Mkw'mYV{g}wabLbL)2 GLBY_ȶA-M+*vL+-`?-ͮ«l W)_nn't,!%i/m~} gL'ScxW<|/h%JJK㻩cRů^r( OyL?(q Ҵx\6'Q\RWUp~Y7\<秽U0:逧 }~~ Ot]$8>v'|a&i%_ g2m~#i{󸬞EqPBWUn۩`൶޶#i¡ /|VS_YAqCTPP|Ϫ\Q1̕U/{;}n>snn]dg/vM/seȽ3 J[C<uEO _uTW{ȟ  >ZN=!p-JRѢkd>|WN}]J3.lɯquM?_#h%91NB֖af+nSF>EeY WS)$rQG|zWD|J>%dQ)4&O_-Eɧ¿ҖmWH%jT>&<΢S,Kɒ*!^"Tw֋r_gk~][O ^Tc)+I1Y!)sHdJ(/te=JQeU6qTkоt?E]9ݙ>iJ*?(& Q˚Vgk:$(tjYnV3ʽS38&k!yvå5^4fi#dTcU]÷~p'*EdW2)t\0eM}gs<\$5oG51Y93^k!g6c8*m:"(%FV8ȝ2E $QԕB!_wu<8XK2oe jf4g1А]|Å|V3Hk+R$˼H S_GYҗH8QYCݤ7q2  f171;~>N=6,9/Ybp% vpB7z`vs U@b}oXOzv6_ 'IᔡZׇ߈H`F7\HJeZZIqH=W\&'$"ȗq5U ? Ž 1 Hm>Zw5b({.Qiq\D璽gTff 7#Sāh5G-呵I|/n׃5E P!?0mB#P]@jHжJȑu)b@ +ΩxXgO_7;4&1ɧ1YIb2mΣS Kɲ{vz97ۓGɧAE ez;TLb,WأqA>|pE qpɲG^aG7 Tk/%duG^??ZG=T+zVm;/xOȧ1YG>W@K>1YJz%OɧS)|J>%O'1YI>ɢoL2:N䷬B~5M1YU3| w'FH_ p7T%m?tL; ,ΎjKo&%6* EW,)kac.qVҽv$D9^*x8_eXNV9 U. {A@t9:^wDQA(q w{; Db@~&T1B_񕐻b Zh)S^|g`Vl>kJl2 :+pp壶%f g>5Wꁸu J,Ϧ@m:"PLV&-yN~ i#+3σݍs: |9,%+Q[Ò_c$c\ wBΥ*"H S!{adJvdeh 'ÙnQ4l~#i#gxR鎟e,!ߋ_g++m~ {/¾Fug^8m'i4l~jb2(* kf۬ؾ]6_'[/!߰B6_TՌKU no|0%j LQUCeFN=η2'~>zY2ۄ;efxbWж#m;6ުC S&}iRne=3 ?:0!HM{IVVkLi *#Dٞ{m;I Fꐯ?7ɗ<\.ȧ1YE |DcW|],zJ$=RϱojnEX_黚|J>%Oɧ_iL%cOc(%EɧQɒ,BPp ,1NɧZcjj=_|Ւx%j$.&W<h* I>wL\N>|ZV2PY@97Lk+Xӎ\CdPn_ibPY ir[-h߮8 ZA>WBje|:fhɒc.6 kP88)$"1gBmIaϧP dj?ɸn7ևʊs0L1康S ĴW K/QF!cмnڼ6TVJ|$4Saxb-$=|!Ș,9QYna?_F1TM~%EbB3DiJ>e'O1Y: j8nBBe?]ׂ5=+򧘅ÁZd|#dQ7(dQ7*Iy'O@:*P)ESZG/zX>\]| \*Jz ?ʼn(K_W1YENvGJ Ȕt@ En_Js"wb#I4Ҍ)< zozoܵFb7k9Jw0:'5@d"_52vð%cPsTXE %!]'_-jz,qaa-jKַTk-p:c!{˥i'K9A Q+sY 㚷p"RB2ȇhL ETb<\.{Zi5&lȧZK9NF~FAv'Eh@K']ӄ<_jU5ew RցteN1@>iT$˗N{~)Y<%=?h,ķ5XDZ k0~>_3KYoy Q+|l^>o4NV QI{48f%G)`rKt#gn4l~v/뮱1N~<7|>S'KvLwlUP|m>߶p#5L P=S/8YZNDю/uL~QBbvE2v$gʈo kWJVOɿLdoJxim'@!mGtm'|w[FV|c`-5'o _r|NɧJL|VLm~~SׅcJ *JoJ۔|{KYtp܊=zߋOߘ#ФS7"MJ>%COR})Zoj=cC,d Ev(^T%ij_dY;X>PlӶJ>ְ1Y"Q5.P0XkJEtMFZI>v(bx31P&c^*UץyE}9SF#c^!aqK?TLVII Dag c^*U$qګ !oQ8JF._btPiKzQoog$CaywQfz f.5iP/P]>o>&b_ywDƇ}#5R@6EWõɲGǼ2l~7T/m<(YZZN˒{~H* J\QhnXg=*b&!_JPJ~Ԩ 4Y"'e^'_QoGajCDIcVVe2)vȎWx_4 & e<,Q!_JPJ~rqR*^āG!!^f&?XpxZ:<UFv#!5Z-$?T>AH >yy$d GN#?7e\I{)ޣB>Z_d dpQlFUAޙy+|7g5gB%Z$w\B@ N.z6:$8yFeXdd6׈ޮ*3ΊM,FQ]m;O8jy!]W#15 _??W&#nO>qVw?,ڞ?JoqH 7UX.TV*z5 cGyS?9UpS$L'/s9rpެ*PL=y;w9ESGb_hO`\*!tBDSd!1ƿj "_{1'k|7-J>%qPo[abCS$ۻ5|kߎx4-O7NrK2L)r|}{uIb~5 K Y ۢ5\hմr(8 _$]Җ#|kpS*8%t.ۦS2} |A1I~wϻðpfʭsͧ,ڋ8KyuL%!DP)|J>%OɧS6dL%1c(^vO%Y7ejsLP.?CdZJjfX:ߨDYi/~ qvJ|wA)Iؓp,:NXǟ!{ WƁ\>WZA Ȅs!ΓNQ3т-E<!?XV*&%ΟGYk@( ކ@c7YYRؐm -䎅8(u{wdUe]y8 s1^',wtp@Υ 7plTfRj;-Nz>Z.$3}y7ϭzC5/N,'i7ArOZͮ?v| IɯdŞ&ȗHQ)8E5`YSF]X'τ-TGX!uˉ7q$Mц. 6W0ta5染ї@V;5,ʦc37뺴c߂;ij[Y-Y ll_s| Y@>j4tV@!4Y0K5M* 询u#Dȇ&hn>']jtOɱ*C܅5YTsfj9W+lxN~Ciri骢1E}їa&YK=Vn#-F|r|]r#hHI.eINǸB/+2-go54l!' ' a2C@>cx>(gu6?Σݻ} O;S N=1e;ɯ?[C4}#4YD`בl->"fک@UmAYF|Fm<R#e;-i?5gxd.t൰-mJÂfBvL/ʮ8:9,Iw I|_VF|obo˩̤(g⮤š/[Sz%鲩~D>nw0xD[%| x .^I Q/mJÂ֦&ڲoEJa:[w{8/ꙥF찷 KTf(fx EB [}ϴ,fY*,#_, %D6"R[ .%T.{IWÉf6aAukӣ$-ɒb9Ths$';ٸT_/2o/B_E]di5YGylqu9d#qrr y"fFV::jpÂ&H!X-E:'pd^?wOF/;/2'Yh/$Dglߦ:&ٚ-ㅰxy/VJ(%Emp!dYn@0s2K~ 6aAukqNқʻҒ|lDLr~Jί%[ IDAT2'&6M18!wG%}O8F~1soW77բ/*O9&u>cC5HS9MiA|]>#9a2 :xⅸ*[_C~&|s (|ݳ|ZW%æSQڏG28E}ݤپ-mJÂrl)H90-JKN7 y:|#v +f'q{MqJ/߈{xx#q|y tHc'EB~[5Yuu*K dβ,4Poou{]涟[5Y*l `^6Nn#Ɏ>Qn"pk4Yac e'E+t<ߤe1 C<#5,ug|r wV_' | M& M?NCKz)_5YW\y_;]I1w~7wd]^qRC<dQU!hAn!]_Ku?]Yh|3m|iS ^F\r_ p^>/ y@}ȇxjp-!"$HݰEC%[K| j&Br_ p~+ov\/!*]2~h3v{M s./ МOijT_jx!H횬Bx%xyZ3u5[!HYiܗ(ܑeӱ;H7 -|"| ^| >YJo | ȇ| h ^|dA&4Yȇ ߪFZ=Au/.YŪs >ߪ± o嫙];R/XŞ?F,ܳ:NA٨=j/qJȉb#vݐY 4:?Fm, jDȏybG.LJMMȪ_zvnYOn&%+q/k4Ys!ņv jA~ϢΔKTqU-|IF/o-xӧFM|T;5,{#?mjls.v]]Qg6#vΎAW^akkȯؤW"UA &kDYFBHo7ԗ|ZE)NN/6de'њQJ Qj.ɃeS]ϲ > f? w>"'fQj^d Q1WcoSN'J wEK;^#fM|;@~?z(CHDs¸/!dC3)||9"E +Y5Y+ևRNpM鞐Hic8}FY6VS&e?Y5@'.#c%-YlՑղm$ 2& tQw2,B~YDYu2M,Yf8ӟ \RWz'[v,PIg2[D4Y-l.ϒ_EE $Z$G(3D3G)=Ȝ=pϥQZp{G_c2Eso>v"#BP_(7޳l"e9ޓ~o"o:u~):S*6o|R'&ܓ9⒒zsڐI >RY4lg_磢7HoY@~D^!fef$Mm^G!x֯7$RoΗ܈NS؎n4ٔwv5,$4YI->Y^ VC<:,1h@{w!Τ ȇxtoɒ#ըSOVOLPBTnSXhUKԗLGtn!>>p>\Aoڔ|:!_oMc)ēhH ɇo$'k1!+SyVB~kѤI' ȇxo`E FB-X IǡNj!O>Yr:S!Z'zE>YYO2 x~CVa-N'5~,FYdQݠHB~ELZ'u!|_| >YLWJAܗ?J>kd$>|Z@ϻAuyk[鋷YַkɧE\<1= [i]i ]sBWJ-V$ CU΅8MN/[[ޗ;ODN { Eg$F ً:_@3\vm}Z8 v\Fh#ɺN>٪grvbJ~:C;91qIůĮߓ[4Yg:q/ƞa&RȢ>BQod\IԻ_B)k&Ov6ât:7E?},oPGSWE:gȿYu+Wΰ\~݃ޅ|=؏NH䓠Gfy{2؎$ϐ&+8cV-VzUlxO:GM1,r6$*jzxLZZt+ߨ XUiU^%_%G qBIxn*ɣV;bl;ȯd:J[U?@rh_t.SMU-@5Y?VI^:ʞH*C@>Ch#ti-D}NVWhž|ly] JK[ 觅.hىӦ ,ug|"&@>?z! | |⽔/h$4YPfկ~Jȇir^\WJi?% .ߨnv[}MWqoda,ӿwUƁ}v#W7"ݕ? d CuL*X@>=ȿMUߵMÁ0 /W(mgk2cu~b, ȯdK7Rp`у D̃촱ݕ>%nb, MVAFt]v b7ؘ,YwW=z@yG|] ȇx3MYj|-dW9?"R'F|.=MUt}ݒ<Aɏ>Y1NUNc;wWu~oLVzJ>c= ;(9 NH2|Qc5؎UN.ݕʱa:bl' \ $k'qQiw!ō.f'yfb;L&ȟEr>y4?Y'w\&?F52c4shA#QWoj'4mQ}3Jn2.uCES]ǏO'+v %x1?H}9;]9l`V)"!_짾ZqO{b]7]{6{~'M_Eǭ'Bd1 S7aef^+ $rTp &~|sV=EE >$ sGϔ)Y),DP'm|뵶9^YH[,6q4IO ZM7u'KGw Qӆ 9 (dEDⰨelv }_5!E5Y|<h 4Ԥ]!R"r7|ۄbLOn&%*x NW,RmR$q-ߴ@ Oq`~9#/s dY o+aY/6-| ;Oh(B>W'u~Bgi򋱝<$u~V/6-| ;?z,1>!~|,Ձ\b_-ϽD> 떬t򽖫ܴ!Ӛ코|9MS@@>@>|$|$& cnnkH.˦@>]ɿYE}Qƙ+OVT,Эf~ߊ)@>#&K:k  aȿUJ>_]Y+"s4~gjd@"jICȇ77j6'cŻpT|T|g˶9PJq'$?0DF>y\9ґz:M |7|6}Y "d.P.oQQ^!?Wx'\8gv4Y 73 *B>WO9?OF1"JN*:aѶu+T;nO4ERzi>n&k@0|bu>=3>'BLmR}zP-̹#!,u`:|*v։WC>r=)#kdnNF'ތ [)(, A?:MրNg?bn[esB|W9Ӭ#ϫձA" Qf} iMVMx)^#3=;@\BK OB>M֕ yb'LooE6Bg:MxǁFp;@>& MA&7d]sV}LL ^OV5TX@>>Y8WaO@|!VŻjZѤՎE/Eg[= >юl'5Rw$S>Y]Wa-nQ+vKbm8pPsٝm.|BvֱC<}JCw^|r4hdLf"GlR_D>ijROViUusث)#lL|54b+Blҳc1S^cM=F@>OViU%ºH~NWr~DC8}!V "j "5@}4Cȇgq'kWbU "K!kǎ {!|d/J>M| | uC=d" G'6 {}UtWۢ#zAujGHn$ms4vҖS"1zAOj4[~ _R5Qjo՚w!/-XmtU<ȏt|O Ҕ]Ά 4Ybϖ]{64鋋ZrlUc:ϮE8c)=~${4Myg ܈,[#ˆUGR|F>Y(,J3CP0 td/GT0;A[Nm ȇ ߞ ; M֯'? 0ˬvlh"q8Y·9$V=cu!oaL?rT'F[I.wda*eYGwUјwe5 tUn[}Y&Hv#Y6,Y9$w͢ϠSvɍVYYGN_i?rf^&+*.:"rh'xvix8yG6o$M]Bz8A>N6UyAꟸ"L'ձUHgc-1-mR,[#pc0 ^PH>{ɯd|=egEIPYh!%n ScHaXteO'{u~ bj!:J"{2L߾[2 I!*, }/od\UeYYМo)8ӭ2a4c3eeCGUQXtx3%pYI^i*v≭ƴI-3KTtkeh͏B͚,} 7F3:iQ5TWn?41eˆahvena9Rw$4ŕF-sc1aIcBU,JBgu~ƏG%ȧ"*Hk H$/*>ZUu`;Q*dS"65US.ώO t6uuEUg kښc.; rf(63zMݺBX %N`8%|&jPǬ$UT~9y:}tvx&oBz7\QZMv oqJ'J w'-=|c\$ӞN/&?Ff7 A@'hsN۩DZ4c]' F&~8ȴ.`Zn$ 4OwM#u:*׺D~ [| MBL●iL9 L AQf+'?֓nHs>k䓐ȟXHV'N"d,'ӖGIdtNqY~Q:FKN9? 7 ԇ=jT>./# 9mVx(Hrg7d!cΡ:Tɧ wzo7͋_>|"um9O~޻ W|<ǵ.;iĚ9 vQǴC:_"9p|itO#|/X2.)Z#$oaA|Bhk| ~<ƚi ?.Q–n{IOB3i mHᐜϞB~ 5V[k:U>./v!^&)llgj!.g|_ewi{}5\.>FL%X-dvS[=đeڣIDATWȇ ɺ)Wz݃/ GȿAv:72۪Co: ȯPfrF\L_CoB+fjj_#?? ^ nn@~,k>Y&1{7,wcuK[+JAÊhAir%W5Yըe{7,*:|_f)s-J~)"W4]M5ŝַE[#_}Z%&n nXB B~[RxEȯh]OG~?5YS bu jm{FR(TdB~EE.ϵo#O#n~f@@>C@@>C@@>OdCbl|v|)uځxRv|)uځxRv|)uځxRv ^-| A@Z! ^/W7VXIENDB`TreeLine-3.2.1/docs/treeline_sm.png000066400000000000000000001370471506556630100172130ustar00rootroot00000000000000PNG  IHDRS~61zTXtRaw profile type exifxڭYDr8;5z䨡W*e"#$`0@s]&Rs_l>xy侾n~_~y>zt___uo7 #z~_wϿX6Z>?|~F_b(>Jkz 4P^|][=c;`5C ^+=bۼߍܼ _oKi͝зo+߿u>^7ۧ;nc_^?ۯ/j{Ϊzaƙfef_~ʪƔvi]vmpI'riU{-bk])v '8IZ3VGǂ {.FӚd,cv>v+ _Y7B-܏U[pWHnI۵L?z |*\w={[Fifp`LqƑH `1YqcJ3E3aK=krRæ+Lbڱ>OlWyoۇcVm;sD=Bl'=éDpΔJ?quo-]ZKqda{6f52x:Zli E34[sǷ]a}9Y;3,05w@ L򽌳x߱eXrsc7]_;59>âGYfN'399 amSd C2U^xBicwMsFW}ar51bq ' u"aj k6d.M|]KXcw;q2y`5Ya20A~ W: N:z GS&ϭU)C?DΪw7_Xv ` "HLȴR'28.d?ua]Gg2ͧ'p,I?,!+fAYnaЁf]X`: 0E(qy6h{]4Sp[;|NY|mx`24SČ+^HK usw{/JiGo8_e39c @>۴mz2MNW akqF88&ce{l!Ԥ` 5 wU{cbḿbvآE@[Xx_/ dȘ=snبuc;}Kga1tH5'p0n*\rLwuAzvf)s.LXlHcUa>}Z0 @I[6Ys3Q'/%"?Y=2힊L[>~Z7ltkh$/c]ĸ=```E[hyȆ1%EE0s x:P˖em`~JzaV.L ͟u@]? 7w;hA3 D> cc^Lo,_z4e,<6 8P!„`2s`jD.ԃI ytӛX'`22YD>񰕎lD+^*.H5'^( pƎW!j3aSN0aMv"*3I%[ Ժ[3v |L :Qܝ/5#W(ap|-$Qr"X! πZ-"߈ ,57ʢf 뵧b\*x6?Ru&0 i2ޑ/#pT)<d3`,Q-0tHD1Y8,ɻÿ3bWƠhcm#f87$\O5deS@oZ 2_s"7:f(P' LZLZtg j*LQ?"e 1?丢iG,&G{f=V5nmU6X޴N0}3]8%)gу!b1Zpx\J=I/B||{ G<͡@"ZHn(`ɬP:%nkP'#LJp38z舔1~H]^ivO'#,M@\#X5!a$Vp߄x n3hGЃ N lE6ぺ&3A@84'XDb@{AX D/8'o4"L‹cH%yiv]O$T8F{!66exxĸ'(2'u͆gQ甊8bZ~*V[B후0TYxsvPJɕc!>D%Kkb)\6%"n"%E}fz0R.)9Ks%k%ZE,ZKbdT)aX;+c6>wm&'Wb)±#sƃu[jkݠFJЌ!tآTsZ2F8]L4mtc&'|m ue%Zc9 4< Z$w"XVxFs|e޽.єņ>=f-f !~F)  '5^C#T vX,Ve*|H*rS2L5L3*2_|* jDFfpL2:"Tr5j#H>7CCV6`n>o6 sp`5b_kb)) (Ň/x6B5='Ɗ:I\fB^0 0: ^"D F LY AL4d'b=XH[nFiudN lzݡ*Y ('2".VA _qUF9`U" Ukm M TXHLxB Li&' =f,ff^R rCB0dVqP?w )DǼꮈ]u۫SPI4K;tbi=l/qGǿ\c5sE cԝPJEjgž D(8lc+*?##\=ȊTPRղb=EjX5unϭO DVme +].͎ &&D{ ['ԗ]`cUn`bMuM -L (04T9ՠ5դTUkBK.cRRG'ө+e5XT+2lKw Trf7`苍oaG&R{|$i3 N:E. mS.<$%TtF+)Cݪ^B㌱"8iNq"ieu Pp&"!h"&8MYpBtQE5u.e=5ՒO iiCӷx=T^ӟD#1`L?2Zu٪:5"`>R ?ꘙy":@}q?IkWStx5,r<@HؖD!.d^黟T*Rbd4f_&o4ggM%{FÌ\d ;-ꘂNd}[#V5 +DvE oq4KQ"A*Bwioޖm<Vn*tVϋ:P(r Qsjl7G9;a+xJgQ > ^] YBzǶLd{Ze"'˴my,ӲBj^.!V:!𨚌S/CF Ѳv'N'O ɍ 913_&, \vɊVm[ekQSnFH'vG8WˊѪ=%9 P"@@nmƇZɫg:#// ޯ>{U ;ٛ~0@T܌ ¬ mQ˺ሢM0 *ڃ:q$?Љh0ZVCYM.N;2:Lo)ܕc`R ԫ*d@}NPX8(mPTrSsO>? ;5xQqCD5Cܴ=,>-xW{Ϲֻ^M/F@W3̓J^%;cWFx2MA@\[-'(btՅDU|@2cXJG'F'tw47턇 elPtvv2`Rj6#{ t̉ЋTe,w't1tD챻u*@eM tFxѠn@Ia[[9 ybXEc٪(%& *sn&Bd4= 7 RZ]u]+t- dGgU޿ 1ĪgZOhk-0;/eXt.kɫ)zPä)=s{i5h;6A 2V@Hp`^zJ;HJr5̷' #v9kRCm7ĎR>ր\gu[ՠ}طSx7nBH'ޠ_؎QgBўD0h 43v 8 GEōXUsYr]pJP<2[8Ef} jȈyjKJIcy tb-Pf,6;5^ {sa! ЗT 2a|wo(&tW>MU&A(arO^QʋE,3 WM=)R6'Y٧Vwʰ$+SԝS|+`Q{tR[;Ӻ*$τ T0e#4 @R3 :]~ʪfB0FuC!ÀOH'W'5}zv;*AcV(n cyQ7'Jc9j->At*SQ0=(0pRaTn X_[ "& +qA'n?8 ۟e;~;z>]kYl=:"lj*fF;_Ve`g_KzWg!FjBC@mj[Mk:My{A{Ң`=@8s(!vk9kmO$lEuL 26 Aؒ6C&@=! *h/dp:6micjES ^Q;P^Z}9R1ש=HC&D;;pdNR`.O.b4jU<(_Wpӆ'xСnW$'$;SZ}'-yc.,P,1a'SrML1RySAs('41{0n>_DF}Bһgj~u2 ~ uU[>RPipjMs7|nqu&!<[[MWΡGFl 8! .L[>gRo8nV cݫ{:vF8y6X\Uճ-<&KX[^8i; 6YuhMYT.p¬cOɠuM"` ;3I Jmj"µ]b-T ^PFզł/W[%B `WfGE#==,ØϾVR?E D'$_9 . 9tuᗷ?kOZ!J<շk\n6>#4:!Vt/ze?G6a:/-~a \7A/Lj3>XExmUSJ7XOۡטr:]SoV>{0B U Ԩ%@iDE 1@࢒"8b,C;vCswsTED8UQs*M텃ɉ*tU&5- lj꭪' :'4H nMaS{*UM4}}ic>e>zPGNp#QSO5t-"ƖDH6JxUDRQjf<ɊXď㺆H( 0\Ӊ C [̌`*c[ټ~&uԠ"=$QTp:G<4DA[:4-rņJɑ d D됈 Nt|HAp xP ټG.P8mQ/< m%+lS~s:emܷ*.RsgPR1"N"*Rw}䮄ӑ*Wm"]5nc 1oR:_"Yyu%qǫYmHbyxŠޏ}_U `oRWG}Y ,Q9 ' 㶷 CݦN1S' JỦ`u7<+'Ys&m4jTVsU;Ʈ"w .T~:MDĬt\6  c[U. mKh"*>`unj̜ztӊ(bj0 &n`uϚQYjM++SJ::@QmnGM)5 ?kpHRiV&tn'\C4PuYD$8ZP7v5*xڢ,at !B˩'F{:AM0C-$Z=)=0ͳס> j#!/,,@h%”t̘`9Xx7u>l$ktQ3z&ܥEbUmg-)Ui+Ҹ߁|=eT4RP$#!)4 ß*VuY*Թ*ˡCE","(ITXQ[vx5؀V]3zw S ƣlyo``.j~nl@nkCӶY38Ty{PʬUGȡ:6ӹz:6VTwdF | `֦G-H[k*rl {Z:(Eu4 GG'r:5{]ɽ_^@u34X=e߇y8P6TUޏM}ww֞g0qEB?lu`ڌ YK'&S6 zEUݯWP ~$8rTռR5'" ;{(0NQ.j&%j6(YLLU?AElvP,(0g#J,BޡCIK&u+qs=P.#WZ*/6'J믜/tbѝ@֦cۮ]PYIN=qU*> gcJN+<@õmZ5~L<3Xx:3cuuT}hJ Gjj\|ra82_w9Samr߇#̟ Pl90OB9޽ϕry*+k+B Z)t5m1 ; PLTEU   )( $  #2"$*"$"%0 +<&(&*9'-3#.=,-+2O:#.*3>@?(4D131 06=4796/:J*.>A3>N59?@>;AH7BR,?"B;FV@HOFHE3P/Yo@/0DMYNPM)\WJS_MT[2b5TVSIKNXe"c>`9j:[]Z+fGIX`m~T][ah0oa_a^/qQC`~ceb\\cK<|9bkwDzDfc.|lnk<~i3{Urmutvspp&ʓtb=20MM{}z,z3$MwP{{@A*vulAIf1v"^[?딖yDg]ŘqAruqg̙ٞKzE$ዱ`֛Ҩmv驫q[٬aůѲy;%ĔaXԳʞQyDĺÿÏLѪp͖ȳ֞s̭ߛٸѿ{ޘXٱ{ tRNS@fbKGDH pHYsuucQ2tIME #VtEXtCommentCreated with GIMPW IDATx}i4@FۤtƊJ-TkE\O_QdaAy/(l'aJ5@e o$J|vU&2+{iLJĂw(* y~]Jϫ+9g~pH·qlwTnQ(rwٺz4?)SY9)/]iܺ٭[ܺWΛ/_ڲ&›[.[ޗx9q8w <2t1c[= >sǖH6oܼycC͓A͓nw2|u^g͛ lJ{\פNyݾ2 Dnݬ56<֜G@ $9nXyuu.li  Rll |f?nhnxl^8PT>n-du3Y(k"Dh杦v6 tYڵ^ofUۢxέ&Yv&H֬1z fnvvfD֭8mFSCLq kn`c3Ys+ٺS!ٮ5}'Wniu3*^?ʍ8Wԝ`,0ẵ[LmS;gFcάSMqli#yL:';^7tn|)sD^vsff晽7u8o[o 3K#$4gdy诎hH5q/W^JL{P;~Ӣ*I{d}u蓎B(y(Xc߉91D𾼋5}۶iԎY/ے>fnIS-N+xw}7s0YՁ3[2p3k0?Jl'ڷ%ɲ ffۈ:ƹV8!\hv36W'w{oݽ{y]{\ksdbBU`i'؊վob[ϮJps{Wɪ{5؜)0U-5J::hYw}j s.ߺ\[Ֆīc~Y]6ьLWU kg}3wU֪^zzsj{VwKْv2Nɱy6ug{I=s5{ {Yfٗr&};~U]Wߞwf\[( mIw=wg0Wz k잻%o1" ޫ9UT #xpwKWV?s6w ق0$4I`N-g|Ýj+WxJKR8w ֭W^]ή2Eٲn=ux\#ymI6̷([(fklq†#'}OHz-:%Uww9r{^ˈ`;W}Dz؛DNfwwp]? []=ag#cXUu[я-f-(6V?@kK/yhHo qloH_% D&=h(ldtn~ƍѶ%ʲ{iV j>\-\s:7n5=sկkwy=wn8OTqOHΥZc{/vÍZv/||pu[Vm՗z畧4rW|;o+JKh1!4:7%4_'x2?5W}.ut/3J@Ε8y/M bƃ΃(",GNu 3-v8 ӂ"'TR T$(wf؋޽H$o>t6`IMhoF(I Fc+$hfT`!kBp'0ȩod$KO EaCDFD& nrҦg"B;J%JLT??GT@l/dT4'xU"O4ۢ46.!阷G)ڍH1NhJT}Ū5+9@jb(i082z##Pb@5H6iT QHayJh"; C)JĞv 5ƪ6gFbzMdnOŊy7HIǼ;ƊXEDќu|շ]s$u3U/]4I _sbGSH:)a7mjjS/r5-ҍh ZMo a!ZWEM(P.JH&&W;nKޱȠ=jDp][=-9qX(cG#gB)9QH'y$)d( a!5j{f@5x mUxipr<[WoK17Q0pDy̝(ϓA +p=-@ um c 7W%6 d*vЉȀG-#`KO&tS\e>>f-o?b Pc;U,G?C4 izc٢! l#O~A&"ԩxM|d&SYrxTV~WTVTS޷*ޤS޷6eJwYUJHuE1WKx|(d"(^[<{_eI)=#7nλr@b1o" wjO)%ydǜ=^%l,OL䱏sroNG8tdyD;{{]{5+M!H'T`2ϞMWz^*uyw+EA& &QqFMQ@]>=wEK8dކj~{\+6R+jz+<}{KF=G ٛ^o:oɑ~rG͟~~CixG;rFwD[pAF(a!@&xLJ=;H6< v$=çNeyz ;?^?ȑR__X Zd;>?v ;c ~+A["|_<ڿz9 H$@^7W>-+U> ~5C7ٹv>4$ ɐMNwۇ (#/:KQR#e^8[nj(>5wO-c= wF&oصKo#>|P^_C)_TZ[o,<կ۸[?;"_mye7w:=Cw߷^{kRËo{7ҏ8 8k~1jHr޽$_#Ξ;w.}^lћo~_G0l3|WD;tRRG,x7{p:Mqh&<{eiɘw_7ۂi!dž]cL}/D^BH!:U:x)dyv_Ά[e-g-^{g塯>c"PZ|w8ҫwc-L\ xKOyٳgU.rvo0I(7;A/~{wKFe~1V;0;ځ!o/-QGnQwrv88|3]1o\z'_8ӛ~77q^;}~/ڿ}^^Gzu:Dg?OC ogN.<+a{Qyi`to!Nwk#QBg_6 ^ ٺI%65M3|2Y:sǟˇqȑc92[{Gay;|8/z~L!r_ W O#޽O?=};~&y%M!O>Q1G?eN.cۋ*Kȳ&xkyl~9( {j;~Wt=|N$^"@P|*sɈd*TE/-χ c={)coTVnGߝcɟN.(ϿaygAyNn>(/-H19DvGA^aAGyuI 24O9b? E(J-P3=(=҈U3AbSjq\x5]yv`"G#DŽ [%Bۃo'K~靧e!__ Bz=y2,z//?ns[]Vfk(Ww)Md ݅ ~$y_f[SOH]zũ2\R𤋮iy֦r[K<㩬tˊX yTnSSSʔTnW'N_QN+L_ڟjz>g'o#2ؾ}}]YtԆ){'N߿=ѣѣ'g?GIG=z/ҐIYE`Ja!q}UG뵚LQc἟SxSGO{Z*=nSG:g'¢!~b;GEL}Im8HI⩉$܉$AyXpBscd ;g*»F\`;z=OE~B818*U/yj( l?FGI7I~jϐ$oS J; }SǠYbCr)QONr9,4)Hb y;(ySso;jy{~O98ԉO޳wdqpNT &i/`EŒ9X%VK8Ԟ==d5EM:Q QjۿgO{ihs$qLņ e . S>AIUװAfv!AM5釛ДݵfOqBGsR sãJ6YY6x8HG|,HB| 8x%+^ŏJ*UQT"v%g%R\jMM[2=))))LyOe{*"oƧr ʐ~IZWKVƼ {˾_FoN~V}NyT!ͧrId3n~mQ;S$}z{e//u^yiRRNO~Ca2߯L5fLzyb>{{x^T*cR-:VǔWDRJ⸷#)!%kW siNtHկa4,<"3 CƩubдf& Lo9 =@ʻu )~D1-5zvDRsT޷\yH|z5fB'vb`ǃ[$ |NÏj?QwSo?o5SJϛJAHNWUE[Ἇ}Ͽ}Hw4u+ײS*X|JqkavJۦi%<ʟSyߧڳtf^8jP^PPӈyf Uh&d޼.2Q X_buU%Y]6T(e/(mśƼ_}j`)@PV) H(-қʛ>cIB䆞N9DьOCUSM>a \׵2VL@|(G4R4@5tMGF9 l'۟P4M oJ #.C";J xo0s&eWkvSJBrJfEJǸ3] 2@TEMB?k6π@R2=T 妗;@dHD `5-սxO~}7inG=dPQUOB > )i<3w,X=vP7Qy76Ӌr#!QQJ Lnk*J}dC}0p!Z?"7ޮtn?qnv{>Y+?~#  zVPeALJ,J ̠z5n~s`L:8GT?Bng&3̒b!$0Ⱥ)9 %Q5B&Q|ɻAP.d*yOxbmSXe;Nα,5X,p0m`*3?]/&(aaA}CyOk,^87›*a-KL ndS7r)ƻ\G_MyޡGD|n<;h?A<fQrGLy?q'IJүzXp_iX@_|PNLwN[򾞼?g<`;?fr6KŃu5!78Q}5с){Eu9_C3& wrDǾk x"!7Ȕ.ѭ'=-΅~>\s1oS Kl~;ٔr李d#`XRj(kT$R}ckAG0tJ зL,scQݗkH8Ms&ay_r*oӬy2ZHi%".htZ2oHmȔ oY2}x^ tb˩\BwsW=BڜMQ¦%GDh.3IFy ]JvQLf[2ZTz"9%]/H-\˖^_=bz?03=ŞWޜ+'c#v( =%]esͦriy#kڢ2AVzLkU9Hs!N()jY (VK_e%t$rYt "sj=ODyU^຤x¹T/ZZSBX|{9x_4Odz0XZa %sϯ*1 SFFVAj@F>= 0XX# 4p&o}4 _l.nm-$jw |NA+c, i yǡMd Y RaWo+ƼcK&G]hmYC)9AL-BBf,ꝕƛ񵗞{,"ONpD@ԵHqix_^ ~O|nȅ9!o3Lu5VõwûwE?/cnxx^{Y0|ZwxL=77w~iт|F~s 􃟛^'TǞ߻5Oܨ7xQ']o_wIO4Ei[Q\u;0V5uŌ] oAO>'˲ yG:/,=`-'|Z2'JͬS8m' ձsUSA G83t\.noޗ}ײw1.]St)SwE]@N`Xn0@:3=@A3CiB"i> Ƌ2%}-nJD_ޮaeu'd@B$N7L"Z:ﭝډd~x?l[.Vs(ʩTYhFmS=<+kAcc{A}(٤>J"y/< lp4 K>cni*rYO)>,l^61#rX\?=Ԝ%amy'߼ ޅ\Wi\ezװsU̖7sc &A~ td$yVPnŀ40Uv EF}S5Es]z5%H[4G~?>EN S%T}Td}88+)c8^* мf &LiAa24nك3DnYP RI 2i$UUZФ\M)[y;&d\φEc@G}-KV lnZUb"ixk2G wR0@6P>9C̋ggj(yZQ0(_NO2~+%oC$UH1R*J ߠ 7a hiZ )W"|8_nme8vZ%Vcێkɑ$`uP-\ywڷ 'NBP~;>vdz"j > 'u-3Sa] 񆃕1H&gr>_"dzrdUU])%oH:- *lAԠ'O Rf+qwGڌ)e{+j:?{zH}/ק4ň$huV.R!hExF "Cn |E9p}!vjWq&?x-f_b\\j46|y{֗^_"r6hJߑ):_R?\(ӱk{xI#u 9˲潢"SOb{Vc"# x"ݩ@ed ;{ >8Ҵ7.lՔ59TZpvޤ7J Dޗ)|ycB@FKsyJo(`/6ٕnqď/F1cr0 9 ĪOўf7Č>/\GU 74+Z<❘":ňZ,3֦v#:^*9TM/ڋJB؈%V&~ 5 iVELeO|1)~|tJ̣My_-o2VvB#Z2¢9h~eyw?UD;,(-TN!<Ҩ,Œ*sQ4K\4aG +UU4k23R OdR{5sB;ڿy̙x4~.3!0$92EABo &x}DZ9hR !40j+}4/n4M@c) qW}^N1rx <ǫa)7K GOCۯ*x:u2y D-u+1H`|:vʬzr4 #bh)jfװ Z3Yl?~şyGf͍uӨ\"B=]C .e5 uT&rCm>A3/syӮ{%ce"^}o(G{] DRVFu_c?FHX΋av;ᣣeY-m7R;0UU;r0ny}{.#+MX卤yY%qU|pjEK]ƻGԒHڏ%|od{\ܐBޡΩ9U%{\X&:Džԩ 0Z=bV1}x\i6aaxag59VSzL_[rzrEq=.CU7F$e-D%)t.CVЪqIKeAkf!(B̉ve$e5uvbL{qq$01L2zmT~(nqUtdJ{\΋X͡9Wڋ?qick/qe^Lq]{<_"Z@'Ѫ@wM0Z <^W( Mqe~=Y]Fä򎬸f)*Jo4k=K=]t}h ,DsEQD(B (8.Y\/%+:1T6T1.I›dzw*@Mm\ȻHd~={4L"Ŋ.y."' &E-\Oo3ޢSn EcjQV|9˹n{RSF}35Lzz^gT(y_)+T̨h%|IB&k'Cy]6ןcf_`I^*By9J 1PcI!""FÐ0d`srJt兿,;'r:]ːU@aޅszn Ǒ3&,HG*!EByIk>.F"&4m+zq"ǥ\zF9z@rbY԰#QMqq)"5njD90J`/3 2ʫ.odj/.GUV*)`*uѽ))ԇY17\) CGIBNkɜ%jK1yǩ?]}|^9/=%+RȐ7H&JMݐi~ûGZ"A$YYFUQlSoWQH_}nyǿ+>?/5hjDCV1SfJ8&,|TR1ѭNC;ʠmO^o{Q@]v5Fme薇,EbܒYYE%~NXYTfc9(zEݼwЯ+U&ŠK(AK޸}'DZ5-[B嫘^kq>=.%|2-qq5Ehqz{C~I{(54 XM%Ѡ<3A@-Vझ;71vろ=\#C{\oKRNzxK'N|?"CEkO%EG~?f0 ~p"k=e*"q  oqyX"M~}<E {\ 1BcukKZާ=M=i"=2~Mn^WoZkA#{\6uxWi3VuǥgY7m{˞Eu_8QnE}jI IDAT`7ϐ˞/aɢk@Ku]`:=kU'EaÐ{Οh4;5ʳ<_6h&zdC6aQʼn!~fM8l  O?vȗ_b%2+ %JD "Lf(đlr_ƈ^6߹eyyܧ%,)aXd{ښIQZ JT Pq\5osf(P-D@V8[9=..-Ř%s49ī饆Bèt5 yrhXfZ >ABUM9# ڕA4LD/L $H޾y#a5f\b7b0v$* RĄsP6 $B: VYt5Iҫ=I{\TIrǕNw%ܬqJw enIK=@LQyQ - Mj˧ܱ6Y,&z#iw}nx*Nݶ(oRqi%JZ=.I͝9٬H\'F$"T,xnc=#S9A{zR Pl#(-Rޒ7 ٚX5г3ӓ`[d]%aN1,vJVofw-SuSvmT =.WAQV#i~"ϋyyuềisף=ɴ41xA²MDlBX\'%bmP4loI}CЦn3!SB~EETbGn.C<5P0uM]p.Rkའ+vKvsiym^_zǨ?^>)-oXoz6?2*6>2J]^]Wt}X3mZ E;ut=GS֟: v$|avd> Kvfot ; -33Mױ =Л+--I)FuOhXpեli!߳^w[gMwdJ#Á G(7Qx@P^0-'Ѥ향Qiu#7Ƙ~)GsҶ퐞"{*&0%Rm<>i94 @%c+!vGf?S1,;,{;.z0rc]$Ba 񎖙Μ`\R#(m*zSW}?ivT fB&`2ȁw ̳K(:ty`o63~=8``8 ֮q*Bرx>|'2TV2jfx) m_"kRtد$ M-x_;շQϋUqb@"=Yl-H.N:=-V;o~Oy|-TAU H5hPCV=瑱-PynwMx{`0WT[\)4ӵ<=⋟ͯo%׶u,\+()˘۔y9ت,Ӭ}sFn]=C'm\t<9귄[z\7|Wԏ<ߣeM/4\ |!%z\%[]9<*H|1>=把 &zQK]^6|z\ZW CU>g*Yhy {:StͰqb-v/z\/++o A "+=.Cz\U~I#8˅K/ 2TLa].e{ 9<5ɒrcp@uGk=%Uquzz5?OյOD4k6GF۵†];];mgz?̺f̳'Ȍ @[ ESn/^/IK 쫝h^J\mIxwozN-=#Sm٬okއjpy7+MwF7uox݀7KwO 6jӾrnI@2š/1ͲsBLjAs^bō@/ql?ϏXej۶qh 0| G䶱:-6.=QkKb=kk7oW|z]!QƊ؞x9sx΢7>՟6K.7 |)>>EdZ~E "Tuԥ!hqOs@,l)]Bi c^я3Wnb*0lb 8>M0ˆ-{و]$Ϛɵ~Y~˴fvC7l_]ߍ>ԐYMlVg.ji]nugbNԢ0yM %h- ]pyA c봇4rfq17JYR"` DO:[rya*5%e0t 2n 3Wg|L3M ބ7l-sH;y :"/4yo}1 v,Jа@F TTNH8?@U0 UIQt)M XHJ7kQl( I+g ~jae7(3罚9y|$B.x,dQ|2^8v^[.: ~T_f\ V2h^Ve=Y4 ϙZq7*aG3 ͐y Rx+تD>; } ކ'ƻ+&Epvm%t7k԰TQuuhwg^6u[š1YV͙ 3g"a*&6:TtUNJƤ]|ͫ6eq5k aAjaI[k9vwrcs/{DST-MS1u]|pBk۽\x* Hb7B|Qsb$LG]#WhrFk}ۀ~_D=f~@(5IG 3^Z6mhBB"츏"d<զ.9זz?Ogo[l8-bd=qSb[nu.??uAWu~_<:5T\x$?_:\ j׉a򉊛;l>7geȶޘik?Azx)n/EaX̪[& 't$ĭd*ga~-1W}7OUP+7G[}e()o w#\mLJxFnH@%q;qw56fZ0^36Ȓ/b"{Cڡd4WS+VvVܺ&;*դΉBزI?bgz6dZ[X[;ĪPH]6^Zej 1t ¹ l+c-ƬhB%1R5pj/yq%:*+Y Yt{=NBOi#c \,[Z.dOTq;Z5VOFNCW!i`{wQ}=Xj(V%L̾ru -Ȉд73sÛ$G97z w2jÍ"$5^"Q#?mzPy5X2qSx(|>h_f%Wkcr2.|.:A:|c$4ΞxWk :2Sxyx zϰJzALޕ84#] *0*;yCL<-h(+:x;nAoѽ"LckZsXh'* l 3@Tt&8+De 1w0(b~_||6^4T%_J۔f)]XHELۚVh?i+\v qUٺ,X͍Yʔ;6̩yw2Y%>$>hnd7o wmY}Է;n=&v[ߖ?>qy*'?b'~z'_cxkϸ!X;qmn G.eg?E|NC"M!\Gk>q!q_WD%-͸@~v-CFz\~n>[2pi^HQcӋ+[@W}XuCuhAl?Uߝ ic\~2r){rG8gӃZWoz\%1>k=E.8o0r8uFmê57a;%;HNǑ-9ʆW:Jݜz\ǥ1zpD=.{Wk?CؽS%S,_|@%[®ƹ 28B`6-yVIxD\F JTEq,JnuLR͌d[* %$WݦǥaH[_>* z\IkqVYq^2ز5՛%hL[ZZ̟A<*ut!,8nuHIZY!̃]=.l %z\jrDžC۠Y=}GH).z\/޿շQy 7p Zq->w^{G=:J9*y6 c^FeuE=uis |{K%FUڿ߀/n0ZD xӊBs#ĵTCÁjX dM,-)Rzxyy,mb5tMR-mE3gn'o# ÂSVTs\SR=Q ɵQVvUS8Ȇ_eۥE&{>i 7~}:z4ʿ>{aӻ??} !79ޟ4Ms t39V%w KSt/رeoe(շrɃ .u-48as퇗OKγ]fyWQ;k<6u΀j|̄A9Zi0WYܺnl5۴¡٘-avADrX~%9PSmzJbG=kHROb:!hI˚g!ZJ# wQ4zCK bP\Bwq{dpe8DcJB|yZ;>;= 6Pf7C6g: $VxGy)zhOZ(}tTԲlJ;E]Jh0MT':ih{`]^DM9ۄk2w ۊCCܦ4FF̳߿+wSv1>VGoK-3BB$Exkc*$ XlŮ61d! VJtMiTu%͒! C#~lKY RW4wԫ2we)J \#IW-:\׃bCܣn0SG޾w(vW{kMxWH4kL%,ʴK7-lāLGƻ[a-UPc{LV itso8ιWؕl=-f`55&/M>W ׼2s644${.kG. *7^m|g!6r2WR^Q/|pc.dށG{[s:tM:7HBSA{n4;U.4]]5r_Y,ؠ^dx)yf۷`$xh8^rqE"j* :p`݄4X)hvQz6M7CÀ]A}vko*\݅͝/w[~~q5pYPMXs-#!:5b{>Mah4Ӊ7Zj5S}__<o)Gi"xLquY:TkDWW"XK^)HӁP9iagr`c*.m䓟};(7w~o@-bQD>zQiK9&q7SG)|{|xXsRoMIo6w^{؅s4ŖGϳƌw¶?x_ /I?_LUΏ~ -/ >lLfnxyUXi9> u8o: 6X\'IDAT1bfBUR+LpůJ"ĖsEG=A 1`N4@Z!Վآ$FO*caF b*66z߬U+,^٥?$Xur8 <ߞŧ˜ā7W;QR"KO+pR}`߻ZiB{^s2'|7Oh];ro^g=udR.Tgkp3Z:oB (.vD؞ȱ56{Jlf|vP^90M^NbWܵ˲\bLV^bKe]PE׼lux@XYhgtgq[\_|qk:.) /f(V-(R1eR\9l\-#QQaAS–,nޒwIvSZ-ZM9di~[͆]ѕ3(U1;&ivWτ+.WW'?i(iv&N{cw>SRt8κ9B LB8uM Pry( PA;l;a\zFtb GcJ?HՏ_Jlxy`j \a tIk 1Plm"D#?z:w ڵ책fjccD QT@ ό A"ڠ!(MDxnv"!Dr!v!z0q ]tHyŸ!-cw6TVT[V?=Y8ԻMۑ~Hyoz ^=/7޾5,3xE$ ҃du!!JT ĺ x׫?_x\ω/f X3z?Q>Y),ft2Qox" 7 6ZG˄x޾?=W'1欈z7-]E w[KC¬Vԭ~ec,-b)&my4n*3wUg4T5usX!MZ[u"\S|wxG};)AD!/Z $G]ڎ*]/N͒ ijE>PPb  ps0gzJPf+`ڧI:;EDZAKk/PQC[Ӻ <3P@5.]/xvuD]ɂcERx#7P~a{W7l- UK88p/7}-?E(k:?4-rE-~ՠB6xW^ftGNW_׿|V%3\#Q.'[{P~mU[[_..`V+j+5`Ӽ.CɟzuN8xL1FYjdm[._we3ᅳ>{vL8=HޓKG /ߓ}_}΢ Tє1ǜzvGTWlޫspͳ~1.~X{DW$ PrX*4ўoqw }7 ^eMV6,"/F'2y'ydzUK]yoc~*|Eֹȇ?lۏIN=?=Wk3ũm?ɨ )ap֨vtXzʁ#55G`oLLh%i"X-?%_]gtӴ/y zEUܖhӪ:6] z nej~+E:)sT$-Pu2y-l5x}wOյb[V!or"ѓ\nYfw&R$۷=a KR-q [(iׂefch2w64']JnpxN`e 3_LRn)䎂 >p)}]+Y 0DvN>U}7HnSK>m:b[g-.nF-X:q8u}Lc^ۡ"۶iߦ-YRaچE lt7V޿;][y ,jK(C6sE[nz\2{Y  K>WܘN#q٦' CFshz\y7,>,ۋ9wb Z'm3zDžR]T{NZ BڃטԬ̂U3T'=!N(GoI6;1B㲃w_ ΂ v}E1I3pYWq5OO~z5?g$jR9+#)mٔ V6ZŅ]~JiFnҝ= 9oO1tÿ&wEBQ)˳$MF @{HҁU\UV5jQ}3K^Dó==26ia(.exxsyNZhhmD=a4Qף3W.k}G^EW4$hޢ~G774ؒs{G}3Mi.՞[A-yѦAH͓[zpW߾ye>OLσkh%y AsQ*m,[j"C{;'*Q;~* TֽUՏ7[i'vBzvMЄFBt.gxQ|*LaK="0< 5vccf:oUL({N2O>O<ynEs*TmӶqs:t㎗xk)wWr|R?qrAmپ o}VEMٟzߴZ]A3os_C}t`?ԌsҘ=n5~ƈacҹ!Pkzkqi4 2Q-o`yg?H T$WFoqjjy* B>4grv0<HzPh̠@x?Mu zQV wyО;~-!̺yfy|cæ}HU\;ELkI@t׬k &Nʵwr/ʽJ$xW}U_E야mE6PǓvѹs}[git%d2p-\FLpghAB^@R'|=7H@"z1%8 Tn$^]fCx0áa{G("`ϋus|iegeyE47kд2˰rmg0 mq[\xppi/x[2o#x%e=HmH-{== )>!oUL\7yw|Fg;?,缗]V\ y?N,ᑥM{95n~<9oiޮ{ũ+uڛf{QkO));FMfyc8^y2 R>r}})ޗr})ޗa jUvݗqKjR>x/c)/?.߼TIENDB`TreeLine-3.2.1/docs/use.html000066400000000000000000001372531506556630100156600ustar00rootroot00000000000000 TreeLine - How to Use
    TreeLine

    How to Use TreeLine

    Contents

    Basic Usage

    Detailed Usage

    Basic Usage

    Views

    Tree View - The left-hand view shows a tree of node titles. Parent nodes can be opened and closed to display or hide their indented descendant nodes. Clicking on an already selected node allows the title to be edited. Right-click context menus are available for commonly used functions.

    Breadcrumb View - The top pane shows the parent and ancestors of the selected node. It is blank if no nodes or multiple nodes are selected. Ancestors with blue text can be clicked to select those nodes.

    Right-hand Views - The right pane is tabbed to show one of three different views of the data. The "Data Output" view shows the formatted text, the "Data Edit" view shows text edit boxes, and the "Title List" view shows an editable list of node titles.

    When a parent node is selected in the tree, the right view will default to showing information about the selected node in an upper pane and information about the selected node's children in a lower pane. The "View > Show Child Pane" command will toggle the display of the child nodes. If the selected node has no children, the view will show a single pane with information about the selected node only.

    When multiple nodes are selected in the tree (by holding down the shift or Ctrl keys while clicking), the right view will not display any child node information. It will instead show information about every selected node.

    When no nodes are selected in the tree (by clicking on a blank area or Ctrl clicking to unselect), the right view will show information about the top-level (root) nodes.

    Data Output View - The "Data Output" view shows formatted output text. It cannot be edited from this view.

    When the "View > Show Output Descendants" command is toggled, the "Data Output" view will show an indented list with information about every descendant of a single selected node.

    Data Edit View - The "Data Edit" view shows a text edit box for each data field within a node. It also shows the node types and the node titles. The types of edit boxes vary based on the field type. Some are just text editors, while others (such as choice fields, date fields, links, etc.) have pull-down menus or dialogs.

    Title List View - The "Title List" view shows a list of node titles that can be modified using typical text editor methods. If a new line is typed, a new node is created with that title. If a line is deleted, the corresponding node is removed from the tree.

    Editing

    Node Menu - The commands in the "Node" menu operate on the selected nodes in the left tree view. There are commands to add or insert nodes, rename node titles and delete nodes. There are also commands to rearrange the tree by changing indent levels or moving nodes up or down. For many of the commands, the descendants of the selected nodes are also affected.

    Edit Menu - The edit menu includes undo and redo commands that can fix problems. Cut, copy and paste commands can operate either on text in the right-hand view (if selected or active) or to tree nodes.

    Format Menu - The format menu has text formatting commands that are active when using edit boxes in the Data Edit view.

    Shortcuts - There are several shortcuts for use in tree editing. Drag and drop will move (or copy if the Ctrl button is held) nodes. Clicking on a selected node will rename it. Pressing the delete key will remove the selected nodes. If desired, these shortcuts can be disabled in "Tools > General Options".

    Files

    Templates - When starting a new file, a dialog box offers a choice of templates. The default has only a single text field for each node that contains the title. The Long Text template adds a second long text field for more output text. Other templates have various fields for contacts, book lists and to-do lists.

    Sample Files - Various TreeLine sample files can be opened by using the "File > Open Sample" command. These have more detail and example content than the new file templates.

    Data Types

    Node Types - Multiple node data types can be defined in a TreeLine file. Each can contain different data fields and have different output formats. See the template and sample files for examples. Nodes can be set to a specific type using the "Data > Set Node Type" command.

    Type Config - The "Data > Configure Data Types" command is used to modify node data types, fields and output formatting. Refer to the Detailed Usage section of the full documentation for details.

    Detailed Usage

    Tree Navigation and Search

    Keyboard Shortcuts - There are several keyboard commands that can be used for tree navigation. The up and down arrow keys move the selection. The left and right arrows open and close the current node. The "Home", "End", "Page Up" and "Page Down" keys can be used to move quickly through the tree.

    Another way to move through the tree is to type the first letter of a visible node title. Hitting the letter again highlights to the next possibility.

    Selection - Multiple nodes can be selected by holding down the CTRL or the SHIFT key when changing the active node. Individual nodes are added or removed from the selection when the CTRL key is held. The selection of all nodes between the old and new active nodes are toggled when SHIFT is held. The active node can be changed by using the mouse or by using any of the keyboard navigation methods.

    The "View > Previous Selection" and "View > Next Selection" commands can be used to toggle through a history of selections, allowing faster navigation through the tree.

    Searching - The "Tools > Find Text" command will search for text within the tree structure. The dialog box has options for searching all of the node data or only the node titles. There are also options for how to interpret the search text. Key words will match nodes with the search words found anywhere in the node. Key full words will only match complete words anywhere in the node. Full phrase will only match the complete phrase in the proper sequence. Finally, the regular expression option will search using Python regular expressions.

    The "Tools > Conditional Find" command will search in particular node types and node fields. Various comparison operators can be selected to exactly match, to match a greater or lesser value, or part of the value. And the True/False operators give the same result regardless of the values. In general, the value is interpreted using the edit format for special field types. Multiple rules can be added, connected with logical "and" or "or" operators. The "All Types" option makes fields from every type are available, so that multiple node types to be part of the same search. The condition will be false for node types that do not contain that field name.

    There is also a quick, incremental search of node titles. By default, it's bound to ctrl+/. Then, matching titles are found as the search string is typed. The F3 and shift+F3 keys can be used to go to the next or previous matches, respectively.

    Filtering - There are two filtering commands, "Tools > Text Filter" and "Tools > Conditional Filter". They work like the corresponding search commands above, except that they show all of the matching nodes in a flat list that replaces the tree view. The nodes can be selected and edited from this view. Use the "End Filter" button to restore the full tree view.

    Searches for Conditional Find and Conditional Filter can be saved in the dialog boxes and loaded again at another time.

    Defining Node Types

    Type List - The "Type List" is the first tab of the "Data > Configure Types Dialog". The list of data types can be modified by the buttons on the right. New types can be added, and existing types can be copied, renamed or deleted.

    Type Config - "Type Config" is the second tab of the Configure Types Dialog. It contains a selection for the default child type. If set, this will be the initial type used for new children with this type of parent. If set to "[None]", children will default to either the type of their siblings or their parent.

    The "Change Icon" button allows the selection of a custom tree icon for this data type. The "Clear Select" button on the icon dialog can be used to set the icon to "None", so that no icon will be displayed for this type. To avoid showing any tree icons, the "Show icons in the tree view" general option can be unset.

    There are also options here for adding blanks lines between nodes, allowing HTML tags in the common format text, and changing the output to add bullets or tables.

    Field List - The "Field List" is the third tab of the Configure Types Dialog. The list of fields within a data type can be modified by using the buttons on the right. New fields can be added, and existing fields can be moved, renamed or deleted. Sort keys can also be defined to specify the fields that are compared when nodes are sorted.

    Field Config - "Field Config" is the fourth tab of the Configure Types Dialog. The field type and its output format string can be set, if applicable to the field. Extra prefix and suffix text to be output with the field can also be set, and a default field value for new nodes can be entered. The number of lines displayed in the editor for the field can also be specified. Finally, an option to evaluate HTML tags can be set to recognize HTML tags in Choice, AutoChoice, Combination, AutoCombination and RegularExpression fields. If this is set, special characters (angled brackets and quotation marks) will need to be manually escaped to show up in the field text.

    Output - "Output" is the last tab of the Configure Types Dialog. The left half of the dialog shows the fields. The right half shows the formatting for the title (used for the node text in the tree view) and the node output. The formatting consists of text lines with embedded fields. The fields are shown as "{*field_name*}". The fields that are selected in the list (multiple fields can be selected by holding Ctrl or Shift keys while clicking) can be added to a format at the cursor position with the ">>" keys. The field reference at the cursor can be removed with the "<<" keys.

    Field Types

    Field Options - The field type and options are set in the "Field Config" tab of the "Data > Configure Types Dialog". The many different field types are described in the paragraphs below.

    Several of the field types use a formatting string to define their output. For a list of available formatting characters, use the "Format Help" button. Entries in the data editor which do not match the format will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with "#####".

    Text Type - The default field type is a text field. It is the most commonly used field. These fields are edited using edit boxes in the data editor view. There are several commands in the Format menu (and also in the context menu) for setting the font style and adding external or internal links. The edit box height expands when re-displayed after adding several lines of text. The minimum edit box height can also be set explicitly in the "Field Config" tab.

    HTML Text Type - This type allows simple HTML tags to be used in the text. Commonly used tags include "<b>bold</b>", "<u>underline</u>", "line break<br/>", "horizontal line<hr/>", and various font tags. Complex block tags should generally be avoided. Carriage returns are ignored and non-escaped "<", ">" and "&" symbols do not display.

    One Line Text Type - This type restricts the text length to a single line. It does not allow carriage returns but does not restrict line wrapping of a single long line.

    Spaced Text Type - This type holds plain text and preserves all spacing. Other formatting of the text is not permitted. It could be useful to use the "Tools > Customize Fonts" command to set the editor font to a mono-spaced font when using this field type.

    Number Type - In the number type, special characters in the format define the display of the numbers. The format uses a string of "#" (optional digit) and "0" (required digit) characters to define the output formatting. For example, pi formatted with "#.#" is "3.1" and formatted with "00.00" is "03.14". Regardless of the formatting, digits to the left of the decimal point are not truncated, since that would display an incorrect result. But use care to show enough decimal places (either optional or required) to avoid problems with round-off error.

    The radix character can be specified as either "." or "," to handle internationalization. For use as a thousands separator, use "\," or "\.". For example, a large number may be formatted as "#\,###\,###.##" or as "#\.###\.###,##". Press the "Format Help" button from the field format dialog for more formatting details.

    Unlike most other formats, the number type also uses the output format for display in the Data Editor. Of course, any new entry with a reasonable format is correctly interpreted (but the correct radix character must be used).

    Math Type - Math field types are configured by defining equations. The equations can reference number fields, date fields, time fields, boolean fields, text fields and/or other math fields. The resulting values of math fields are automatically calculated for each node. Various mathematical, relational and string operators are available. The results can be numbers, text, boolean, dates or times.

    To define a math field equation, press the "Define Equation" button in the "Field Config" tab of the "Data > Configure Types Dialog". This brings up a dialog with fields to reference on the left and math operators on the right. The "Reference Level" pull-down determines whether the reference is from the same node, the node's parent, the root node, or the node's children. The "Result Type" pull-down allows arithmetic, date, time, boolean or text results to be chosen. The "Operator Type" pull-down allows numeric, comparison or text operators to be shown in the operator list. The down-arrow buttons below the references and operators add the selected item to the equation text below. Portions of equations can also be typed directly in the equation text line editor.

    References to child nodes must be enclosed in a grouping function, such as sum, max, min, mean or join. A math field can contain a parent or child reference to itself, but not a same-level reference to itself (a circular reference). The references only contain the field name, so they will reference a parent or child field with that name even if it is a different node type.

    In equations, date fields are represented by the number of days since January 1, 1970, and time fields are the number of seconds since midnight. So date fields can be subtracted to give the number of days elapsed, and numbers of days can be added to or subtracted from dates to result in new dates. Time fields can be subtracted to give the number of seconds elapsed, and numbers of seconds can be added to or subtracted from times to result in new times.

    The "if" comparison operator can be used to make the result depend on the value of another field. The expression is written as "true_value if condition else false_value". Of course, the "true_value", "condition" and "false_value" strings must be replaced with valid fields or expressions. If this operator is inserted from the operator list (under comparisons), it will include parenthesis as placeholders. These parenthesis are optional in the equations.

    The "join" text function is used to combine text from several other fields (or from child nodes). The first argument to the function is a separator string that is placed between each piece of text. The remaining argument(s) are the text to be joined.

    By default, math fields are shown in the data edit view, but they are read-only. To hide them, uncheck the "Show math fields in the Data Edit View" box under "Tools > General Options > Features Available".

    There is also an option under "File > Properties" that toggles whether blank fields are treated as zeros. If checked (the default), a blank field that is referenced by a math field has a value of zero (for numeric operations) or blank (for text operations). If unchecked, any blank references also cause equations that reference them to be blank.

    Numbering Type - This type (not to be confused with the number type above) provides fields that are automatically filled in with the "Data > Update Numbering" command. The "Format Help" button in the field format dialog shows the output format options. A single format level will result in a simple sequential numbering scheme. Use of the "/" level separator will result in an outline-type numbering with different sequences at different levels. Use of the "." section separator will result in a "2.3.5" type numbering scheme.

    Since numbering fields are automatically populated, by default they are not shown in the data edit view. To show them, check the "Show numbering fields in the Data Edit View" box under "Tools > General Options > Features Available". When they are shown in the data edit view, they show up in section numbering style, regardless of the output format.

    Date Type - In the date field type, special characters in the format (all starting with "%") are replaced by elements of the data, similar to number fields. Press the "Format Help" button from the field format dialog for formatting details. Non-special characters will be output as themselves.

    There is also an edit format under "Tools > General Options > Data Editor Formats". This controls how date fields are displayed in the Data Editor view. Generally, entries in the data editor with various formats will be correctly interpreted regardless of this setting, but dates must use the correct day-month-year sequence. Also note that the date editor format does not support days of the week.

    A default initial field value of "Now" can be used to enter the date of node creation.

    Time Type - In the time field type, special characters in the format (all starting with "%") are replaced by elements of the data, similar to number fields. Press the "Format Help" button from the field format dialog for formatting details. Non-special characters will be output as themselves.

    There is also an edit format under "Tools > General Options > Data Editor Formats". This controls how time fields are displayed in the Data Editor view. Generally, entries in the data editor with various formats will be correctly interpreted regardless of this setting.

    A default initial field value of "Now" can be used to enter the time of node creation.

    DateTime Type - The DateTime field combines dates and times into a single field that is useful for timestamps. Special characters in the format (all starting with "%") are replaced by elements of the data, as in date and time fields. Press the "Format Help" button from the field format dialog for formatting details. Non-special characters will be output as themselves.

    The DateTime edit format is uses the date and time formats located in "Tools > General Options > Data Editor Formats". The date and time formats are combined, separated by a space character.

    A default initial field value of "Now" can be used to enter the date and time of node creation.

    Boolean Type - This type gives two choices corresponding to true/false values. The format help menu includes typical values such as "yes/no", "true/false" and "1/0", but users can also enter their own word pair. The data editor boxes will accept either the currently set format or any of the typical values.

    Choice Type - The choice field type allows for the selection of text items from a pull-down edit list. The formatting strings for these types list the items separated with the "/" character (use "//" to get a literal "/" in an item). Entries in the data editor which do not match the choices will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with "#####".

    Auto Choice Type - This field type is similar to the choice type, but without a format string. The entries in the pull-down menu are automatically generated from all previously used entries. Any entries that are typed will be available in the pull-down menu for future use.

    Combination Type - This is basically the equivalent of the choice type with multiple selection. The formatting string entries are separated by the "/" character. The pull-down menu shows check-boxes that are checked for currently selected nodes. By default, the selected entries are output separated by a comma and a space. This can be changed in the "Type Config" tab of the "Data > Configure Types Dialog". Click the "Show Advanced" button to see the separator setting.

    Auto Combination Type - This field type is similar to the combination type, but without a format string. The entries in the pull-down menu are automatically generated from all previously used entries. Any entries that are typed will be available in the pull-down menu for future use.

    External Link Type - This type can support various link protocols, including http and https for web pages, mailto for email addresses and file for local files. A pull down dialog in the data editor allows the selection of the protocol type and the entry of an address and a display name. In the edit boxes, the display name shows up in [brackets], and it is used as the text of the link in the output view. The "file" protocol also provides a button to browse for a path and buttons to choose either absolute or relative path names.

    Clicking on the link in the output view or choosing "Open Link" from the right-click context menu in the edit box will open the link in a web browser. In Linux, setting the "BROWSER" environment variable to a string like "mozilla %s" will result in the desired browser being used.

    Internal Link Type - These links create shortcuts to select nodes elsewhere in the tree structure. To create a link, click the pull-down arrow and then select the target node in the tree view. The display name is shown in brackets. It is initially set to the target node title, but it can be edited. The right-click context menu can be used to clear the link or to select the target node.

    Clicking the link in the output view will select the target node in the tree view.

    Picture Type - These links add referenced pictures to the output view. A pull down dialog in the data editor has a button to browse for picture files to be linked. It also allows absolute or relative paths to be used and has a small image preview.

    Regular Expression Type - This type allows arbitrary format strings to be matched that restrict the data to a particular format. It uses Python regular expression syntax. Entries in the data editor which do not match the format string expression will cause a blue triangle to show in the upper left corner of the edit box, and the output for that field will be replaced with "#####".

    Output Formatting Details

    Output Format Examples - Here is an example of output formatting for a book list:

    "{*Title*}" (c) {*Copyright*}, Rating: {*Rating*} {*PlotDescription*}

    Each of the field names in enclosed in {* *}, curly brackets and asterisks. For more examples, see the sample files that can be opened using the "File > Open Sample" command.

    Title Formats - When a node in the tree is renamed, the program attempts to match the title formatting pattern to set the appropriate fields (the same title matching occurs when editing lines in the "Title List" view). If the title formatting is too complex, it may not correctly guess the intent. Things like adjacent fields with no characters separating them should be avoided unless you do not wish to rename nodes from the tree.

    If the text data used for a tree view title has multiple lines, only the first line will be used as the title.

    Skipped Output Lines - If all of the fields in an output format line are empty for a given node, then the line is skipped. No blank line or embedded text will be output for that line. Note that this does not apply to a line without any fields (only embedded text). Also, when a line ending with a <br/> or an <hr/> tag is skipped, the ending tag is retained.

    HTML Tags - By default, the "Allow HTML rich text in formats" option is unchecked in the "Type Config" tab of the Configure Types Dialog. So any HTML tags are treated as plain text. If the option is enabled, simple HTML formatting tags can be used in node output formats.

    Commonly used tags include "<b>bold</b>", "<u>underline</u>", "line break<br/>", "horizontal line<hr/>", and various font tags. Complex block tags should generally be avoided.

    Other Field References - References to fields that are not contained within the node can be added to the output. Pushing the "Show Advanced" button on the "Output" tab of the configure dialog makes a reference level selection become visible.

    If the reference level is changed to "File Info Reference", fields containing file meta-data can be added to the output. These include the file name, path, size, modified date and modified time. These special fields are shown as "{*!field_name*}" in the title and output format editors.

    There are field references to various ancestor nodes (parents, grandparents, etc.). These require the data type of the reference to be specified. This selection determines the field names that are available, but the data from any type with a matching field name will be shown in the output. References to fields from parent and grandparent nodes are shown as "{**field_name*}" and "{***field_name*}", respectively. There are also general ancestor references, shown as "{*?field_name*}", that take data from the closest ancestor with a matching field.

    References to child nodes can also be added, shown as "{*&field_name*}". These also require that the child data type be specified. The child data becomes embedded in the parent output. The child data is delimited with a separator string defined on the "Type Config" tab (with show advanced active). The separator defaults to a comma and a space, but can be set to <br/> or anything else.

    Finally, a "Child Count" reference can be added. This field will show the number of children ("Level1" field) or grandchildren ("Level2" field) of a node. These are shown as {*#Level1*} in the format editors.

    For examples of these fields, see the "sample_other_fields" file (by using the "File > Open Sample" command).

    Math Fields - For more complex output formatting, the math field can be used to combine other fields using various mathematical, relational and string operators. See the Math Type section for details.

    Type Format Details

    Generic and Derived Types - Data types can be set to derive their field settings from a generic type. This allows types with different output formatting to always use the same set of fields. Any changes to the generic's list of fields and field types are automatically reflected in the fields of all derived types. This does not apply to a field's output formatting, which can still be set independently.

    There are two methods for creating derived types. First, a derived option can be selected when copying a type on the "Type List" tab of the "Data > Configure Types Dialog". Alternately, a generic type can be specified from the derived type's "Type Config" tab of the dialog if the advanced functions are shown.

    Conditional Types - Conditional expressions can be used to automatically assign a data type based on each node's content. Conditions can be assigned only to a generic type and its associated derived types. This allows the automatic assignment of different output formatting or different icons depending on each node's field data.

    The conditional dialog box is accessed from a button on the "Type Config" tab of the "Data > Configure Types Dialog" if the advanced functions are shown. Each line of the condition includes a field, an operator and a comparison value. The operators include equality, greater than, less than, starts with, ends with, and contains. There are also True and False operators that will toggle the type of all nodes simultaneously.

    For special field types such as dates, times, and booleans, the comparison value should be entered in the same format that is used in the Data Editor window. In general, the starts with, ends with, and contains operators should not be used for these special fields, since the comparison is done using an internal data representation. Dates and times also support a special comparison value of "now", which is always interpreted as the current date and time.

    The "Add New Rule" button is used to add additional condition lines. The lines can be joined with "and" or "or" operators. The "Remove Rule" button deletes the last condition line. If only a single line is present, the "Remove Rule" button completely removes the condition.

    Conditions do not have to be set for all types in a family. If no conditions are true for a node, the program will select a blank condition rather than a false one.

    For an example, see the "sample_conditional_todo" file (by using the "File > Open Sample" command).

    Copying Formats - Another method for changing data type formatting is to copy the formats from another TreeLine file. This is done with the "Data > Copy Types from File" command. All types from the chosen file are copied. Any types in the current file with matching names are overwritten, but types with unique names are retained.

    Child Type Limits - In addition to setting the default child type, the child node types that are available to be set can be limited. There is a pull-down list of child type limits in the "Type Config" tab of the configuration dialog if the advanced functions are shown. Only checked types will show up in the type lists when using the "Data > Set Node Type" command on a child node.

    Tree Data Operations

    Sorting - The "Data > Sort Nodes" command can sort nodes based on either node titles or key fields predefined in the node type configuration. The predefined sort fields can be changed in the "Field Config" tab of the Configure Types Dialog. The "Sort Keys" button brings up a list of fields that define a sort key sequence. The fields higher in the sequence have a higher priority. The direction for each key field can be flipped.

    Numbering - The "Data > Update Numbering" command updates the contents of fields with a special numbering field type. The field's output format defines how the numbers are displayed in the output, including whether individual numbers, outline numbers or a section numbering scheme are shown. See the Numbering Field Type for more information.

    Note that numbering fields are not shown in the data edit view unless "Show numbering fields in the Data Edit View" is checked under "Tools > General Options > Features Available". When they are shown in the data edit view, they show up in section numbering style, regardless of the output format.

    Find and Replace - The "Tools > Find and Replace" command can be used to change the text in several nodes. The search text and replacement text are entered. Searching can be based on any match, full words only, or a Python regular expression. The operation can optionally be restricted to a particular node type and to a particular node field.

    Replacement using regular expressions is quite powerful. Searching for ".*" will match all of the text in the field. The replacement string can contain back references that consist of a backslash and a number. The back references get replaced with the corresponding parenthesized group from the match. For example, "\2" will be replaced with the text that matched the second group of parenthesis. The "\g<0>" back-reference can be used to substitute the entire matching string.

    Spell Check - There is a spell check command in the "Tools" menu. Use of this command requires an external program to be installed (either aspell, ispell or hunspell- see the System Requirements section). If there are any misspelled words in the selected branch, a dialog will allow the word to be ignored, added to the dictionary, replaced with a suggestion or edited. This will spell check the text in all data fields of each node.

    Cloned Nodes - Cloned nodes are used to duplicate sections of the tree. Editing their data or child structure in one location changes all locations. When a cloned node is selected, multiple lines are shown in the Breadcrumb view, showing ancestor nodes that have multiple parents. The selected node will appear black (not a link), but its clones can be clicked to select their location in the tree view.

    Cloned nodes are created by copying nodes or branches and then using the special paste clone commands found in the "Edit" menu to paste them elsewhere. The clone link can be removed by deleting the nodes or by using the "Data > Detach Clones" command to convert them back to regular nodes.

    Cloned nodes can also be created automatically by using the "Data > Clone All Matched Nodes" command. This will convert all identical nodes in the tree structure into cloned nodes.

    For an example of cloned nodes with multiple parents, see the "sample_genealogy" file (by using the "File > Open Sample" command).

    Category-Based Arrangement - The "Data" menu contains commands for arranging and flattening the data by category. These methods are used to automatically add and remove levels of nodes below the current node in the tree.

    The "Add Category Level" command allows you to select one or more of the fields that the child nodes have in common. These fields are used to create new parent nodes for the children, grouping them by common categories. For example, in a list of books, picking the "author_first_name" and "author_last_name" fields will result in a tree with the books under new nodes for each unique author.

    The "Flatten by Category" command is almost the opposite of "Add Category Level". It eliminates any descendant nodes with children, transferring their data fields to their children. It will rename fields instead of overwriting data with the same field names, but this command is most useful when the children and parents are different types with unique field names.

    There is also a "Swap Category Levels" command that will swap the child and grandchild nodes beneath a selected node. A child node with multiple nodes under it will become cloned under each one. Any existing grandchild clones will become individual nodes with multiple children.

    Printing

    Print Setup - The dialog for print setup contains four tabs. The first, General Options, includes settings for what part of the tree to print, whether to include lines to child nodes and whether to allow page breaks between a parent an its first child node. It also has place to set the printer queue, to make pagination and print previews more accurate. The second tab, Page Setup, includes paper size, orientation, margins and columns. The third tab selects the font for printing. The last tab, Header/Footer, defines text and file data meta-fields for inclusion in headers and footers.

    Print Preview - The Print Preview window shows how the printout will look with current print settings. It can be dragged larger to show more detail, or the zoom settings can be changed. It also includes buttons for the Print Setup dialog and for printing.

    Print to PDF - This command prompts for a path and file name to export a PDF file. It uses the current printer settings.

    File Handling

    File Compression - A TreeLine file is in a JSON text format. There are options to compress the files (gzip format) to save storage space. Individual files can be set to compressed mode from either "File > Properties" or from the file type pull-down in the save-as dialog.

    File Encryption - There is a file encryption option to password protect TreeLine files. Individual files can be set to encrypted mode from either "File > Properties" or from the file type pull-down in the save-as dialog. The encryption uses an SHA hash function as a stream cipher - it should be fairly secure.

    Auto-Save - An auto-save feature can store unsaved files with a "~" appended to the file name. The backup files are automatically removed when the file is saved or TreeLine exits cleanly. The auto-save time interval is set in the general options. Setting the interval to zero disables this feature.

    Saved Tree States - When opening a recently used file, TreeLine will restore the states of open and selected nodes. This information is stored in the user's TreeLine configuration files. If desired, this feature can be disabled with a general option.

    File Import

    General Information - A TreeLine file is in a specific JSON text format. Other types of files can be imported using the "File > Import" command, which will show a dialog box where the type of import can be selected. Alternatively, using the "File > Open" command with a non-TreeLine file will also show this dialog.

    Text Import - Several different text formats can be selected for import. Tab indented text creates a node title from each line in the file, structured based on the number of tabs before each line.

    The comma-delimited (CSV) and the tab delimited text tables use the first line as a header row to create field names, then each additional row becomes a node with field data taken from each column. The CSV import with level numbers creates a tree structure from level numbers in the first column that are incremented to show child relationships.

    The plain text, one node per line import creates a flat tree of node titles.

    Finally, the plain text paragraph import creates long text nodes from text separated by blank lines.

    Bookmarks Import - TreeLine will import bookmark files in both the Mozilla HTML format (Firefox browser) and the XBEL format (Konqueror, Galeon and Elinks browsers). Each bookmark becomes a node with a name and a link field. Some information in the files, such as visited dates and icon references, is not imported. For an example, see the "sample_bookmarks" file (by using the "File > Open Sample" command).

    Old TreeLine Import - Files from older versions of TreeLine (1.x or 2.x) can be imported. These files are in XML format and generally have a ".trl" file extension (current files are in JSON format with a ".trln" file extension). Unlike other file imports, these older files will import without showing the import dialog box when using the "File > Open" command.

    Treepad Import - Files from the Treepad shareware program can be imported. Only Treepad text nodes are supported.

    XML Import - TreeLine will import and export generic XML files. These routines do not have much intelligence - each XML element becomes a node and each XML attribute becomes a field. XML text content become fields named "Element_Data". This lets TreeLine function as a crude XML editor.

    ODF Import - TreeLine will import Open Document Format (ODF) text documents, from applications such as Apache OpenOffice and LibreOffice. The node structure is formed based on the heading styles assigned in the document. Any text under each heading is assigned to that heading's node. The import filter is intended for simple text outlines only. No formatting is maintained, and objects such as tables and pictures are not imported.

    File Export

    General Information - Files are exported using the "File > Export" command. This will show a dialog box of available export types and options.

    HTML Export - The HTML export subtypes can export to a single page or to multiple pages. The single page export contains all of the indented output. A navigation pane on the left with links to anchors at node positions is optional.

    The multiple HTML pages export has one web page per node. It includes a navigation pane on the left with links to the pages with sibling, parent and aunt/uncle nodes.

    Multiple HTML data tables export creates a table in each HTML file that contains the data for a set of siblings, as well as links to the parent and child pages.

    The Live Tree HTML export uses Javascript and CSS to create an interactive view. Nodes in the tree can be expanded and collapsed, and a separate pane shows the output for all descendants of the selected node. The first form of this export creates separate files that are linked to the existing TreeLine file. These files are intended for use on a web server (browser security usually prevents local access). The HTML file stores the relative path from the TreeLine file to the initial export directory, so this relationship needs to be maintained on the web server. Only the TreeLine file needs to be replaced to update the data (re-export is not required).

    The second form of Live Tree export creates a single file (with embedded data) that can be accessed from a local web browser. It appears the same as the first form on the browser.

    Text Export - Data can be exported to tabbed title text, comma-delimited (CSV) tables and tab-delimited tables. These formats are the same as the corresponding import formats.

    There is also an unformatted text export the dumps all of the output into a text file without preserving the tree structure.

    TreeLine Export - Files can be exported that are compatible with older versions of TreeLine (1.x and 2.x), with a ".trl" file extension. Some newer features, such as cloned nodes and multiple root nodes may not be completely preserved. TreeLine subtrees can also be exported to save just selected branches of the tree to a file using the current TreeLine version.

    XML Export - TreeLine will import and export generic XML files. These routines do not have much intelligence - each node becomes an XML element and each field becomes an XML attribute, except for fields named "Element_Data" that become the element's text. This lets TreeLine function as a crude XML editor.

    ODF Export - TreeLine will export an outline to an Open Document Format (ODF) text document, compatible with Apache OpenOffice and LibreOffice. The title of each node is assigned a heading style at the appropriate level. Any other text in the output of each node becomes normal text under the heading. The export filter is intended for simple text outlines only. Any HTML formatting is stripped, and objects such as tables and pictures are not supported.

    Bookmarks Export - TreeLine will export bookmark files in both the Mozilla HTML format (Firefox browser) and the XBEL format (Konqueror, Galeon and Elinks browsers). TreeLine will look for a link field in each node that becomes the target of the bookmark.

    Customizations

    Options - TreeLine's behavior can be modified with several settings available in "Tools > General Options". Most of these options are covered elsewhere in this document.

    Keyboard Shortcuts - Keyboard shortcuts can be customized by using the "Tools > Set Keyboard Shortcuts" command. Simply type the new key sequence with the appropriate field selected.

    Toolbars - An editor to customize the toolbars is available from "Tools > Customize Toolbars". The number of toolbars can be set, and the buttons on each can be defined.

    Fonts - The default font used in the application can be set using the "Tools > Customize Fonts" menu. There are also options to specify fonts used in the tree views, the output view and the editor views.

    Tree Icons - There is an icons directory in the user configuration directory ("~/.treeline-x.x/icons" on Linux, "Users\<user>\AppData\roaming\bellz\treeline-x.x\icons" on Windows). Image files (PNG or BMP) placed into this directory are available for use as tree icons.

    Translations - Translations of the TreeLine GUI are available in German and Spanish. The translation should load automatically if the OS locale is properly set. Alternatively, "--lang xx" can be appended to the command that starts TreeLine, where "xx" is the two-letter language code ("en", "de" or "es").

    TreeLine-3.2.1/icons/000077500000000000000000000000001506556630100143465ustar00rootroot00000000000000TreeLine-3.2.1/icons/toolbar/000077500000000000000000000000001506556630100160105ustar00rootroot00000000000000TreeLine-3.2.1/icons/toolbar/32x32/000077500000000000000000000000001506556630100165715ustar00rootroot00000000000000TreeLine-3.2.1/icons/toolbar/32x32/dataaddcategory.png000066400000000000000000000040121506556630100224140ustar00rootroot00000000000000PNG  IHDR szzIDATxilTfx< !,bIE E")- ?IUUi(j*UBB&B0K ئ2f x^f<孷?@i}W:syI5kwX4@# &MԬ1 XT55kwx 0` Hmiv|`Y@\PZ]UPZ}I-(j顄IF @ @C~vpxty?y/6nl]7}$PPvvU r~}{zBJL 4:m/VOO:Xm;-~mAu˾QVIi&#sMShOEtAg77]>}N Kʼج2B$I1Y7(1 ]kvٚ˒aaq*BN|N),Â!T]դ{`\YVT.{H/#ONrG{᧟H)Jikj^(SDv2 i`vKRtlڃ/?LJEwh`Q5h,b”x\V=E5ͽ?|6y*,9,뙿˅͝$IAg.ce5{m,%hs^BշW?=w]^e<FthEďo-* ۿ`G-#Ȳ_m(jgOOdA[ ؞dYEfz5H@Y)T]] s,sߦnÐM#):kYXX² {W^ߺezSd0[taD*۶~ՅBKmC83yrMΟ(b9řߙ04c0QS'OƮ,4r7ɻ&u.=G^*"$iuOFn@s(`<ۛNAY+Y_kKqqySq8pڈCA4ՄqUĦ p9.K 6,H)o Y)w!6Ea(]4C$E¡]& [ 4$J0Al*:Gkof8ˆvø]$)P$ 4uHD ˕ >2D8ތ"0*75kxЍ_O eۄmldPuiHqSA:2IÀmR@4D^I[/6G"[+[x3#}$geMYp5_U )!]hni(5kVAG%,vAWNr gN85G1ZyrtMMKtŊe@<2NiRNcԁ1La&rMSm^E]\i7ŋc'N/&Iվ))<p,Eݸ4s$}}}3ii[G˗1)r$j]Qhj }~+ֆH>҂ `SWWǂyw<͊Jf4cg<|j_Xװ]߾̓^‘ ͘A[Gǘα xlB,b27ǒf*8ma7'?byqPO#444Pp=+;CAhcf%9z3_`̭|1#V ]̓=SWW="[BN~=DqgŊRa &o֚d9仞S-4i ',ϲװl0"pIs4 /XfZwY5wNo; (& F_g 5Ij5u<"βzf 0`T dfkH@@h$HD[' R'}\.[ &'3Lň#O`%d {N`/*l/J b<2D!kb3Hj߫"/死:1 .9hXgZi:FR8tsk> TG(Y#4IgyV9}GfJԈb^?d IHHHPB1>6{-Gkb)W6B቏d r6ճ6jc@@n+$" ȩzKB.aRZ@>;rB3I:B u^srQ` Ll(pe Rb=p!g$jK}hi `8 LO |qE@ f@Dpq6V {+"X&W&L øTT'RC L͙a15L"CtAhT600 h9ѽ{q8˥?{Wr>MeȔT)`H*THM!fI eD IENDB`TreeLine-3.2.1/icons/toolbar/32x32/dataconfigtype.png000066400000000000000000000040231506556630100222770ustar00rootroot00000000000000PNG  IHDR szzIDATxڭ l33{5^k w.▖*!BT"Um404jd$-jdE&!i\mw]8O?{o70ﺒO79UUzzl&+g-v[*C1> ;ϓc\+0/NOyh[;w`G;hpTAGwpN({e#zҧ6eSwOU1ѹvrѠTB/;zfYXح2cG?r~v%\sM(`0uH*8rEiF}grXPƻBRS0ht3Wqu +nlh2Lq1YN M/%+ȱ]ԱmR7j`4'T8-.D_zMz'_ҷ6/nqnv69hftڰDZPW0:ݚKDM}%I |7fvcutK#,"op!(,3#6=aO?.5GD!D7F*|K집=lW™620+X0QIyRE6jGD29ψ I91K|mWr&v%d`S\i>@\:^ǩ?,8v{lF/dTo?mFYifqX"` &{WX[$ÕDMM WY%fu2tʵ1Z6=Mm"|զ$AV \#a{[ߧh\~iVEPSt3j?]z' "@Q PlAeK1 4{zs:FKF}7?؜K!:yMw>DDE;u?Eb<8ܲ(y zZ2D9u53X;(Ab(}`D\kIl^ZfM yHLhȦd'=hh%[7 [OZJqAE\W~d4/U^ڷjqt+-&)I>ipQP3겂inBշ8tuQ$YmCFӖGi.^lLV6#;p= )CzUXMˣ:l?E(i)Ǯ/pm~]* 6EjP&  2XPҿQ`۩I7 ˜,Z4T[lEQިG@Uѓv#*!4!S(

    eSwOsy$,0 (8\$ x̢zdB0&mRUk3j ED׿J28%\[/@*3W* |[QH4}Ա%^R<+J6j;6N2&IENDB`TreeLine-3.2.1/icons/toolbar/32x32/datacopytype.png000066400000000000000000000040261506556630100220070ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME 2*&|IDATXíkq/ UD`cS45򧖦7i(Vhj/&M6MjiDEc"]vY؅{8{2&g~>;'73 *z"Lk<=R$wdӋC|vmrY֪- IΫaV?'8'tovk ߹$ϝ< z,)3L ۂ-)!}{Bcłi'IIof~cn5n`)%[ %lqH e)?O=|bϕ Wc 4mc`pch'9k.~ZokKՁ0e 0 h#A"  RM|LI>p0sc/*sഡ(hȳ -l&ҚPVB lZL%/~0p,|)%P`d0!6KaO/&0G}LBPr7 =>2.+{XH#21nhxh670oܴH hH|6}ΊumiwdT޶eЖt {H1%t_8Owlx侎-- a,r~ࡒX:Z$Ux뱌^P G9| :Wm91zDzH@ ASX27x,OWyl+^<؛g>E]Ͷ3bq(g2Fx.ԇP@Mʅg_W$4tYsh8Tm]B|8S Hf;\0.uN]G蕍> 4JV!j6cAg-5L 8 \^g36r*쨯=Kh^3D5p`0z7"GC'a(SnK6c #>Ps<~"sR`+Du`[`"cƳU@5l9JH݇O)X &oq+j:jKLEIJqUtஎٵKJ& !BTm&B:rgO5E!Pp4F<.^̮3XR j-:C)*yyI[ ,+\W{9oRrR:nz~t||]@kE%p,Gnby_^*ٖ|녷.[Rg g'qŤgJ5sR{4(i<8>? w{yd&f+/7fjF's4r١/b|v8 ktvi~-?=\Y>{v5ܫ䣑p%=m&u.#\IENDB`TreeLine-3.2.1/icons/toolbar/32x32/datadetachclones.png000066400000000000000000000026021506556630100225650ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME +dKIDATXí_lE?ٹj0)1FDh%KV(B !`/$>FʟQ(Zw3>u$;ߙ} M;b}Sk~_ʕ+o*3L;nv5{0pVYA@H 0c~kYH$bI[[dի;?y^ X>6f2f۽XWY3&òKillի|qbN$܍jfkWм%cߛs_Yɖsn'Qmj p  \"ʈ  b$|ڃyH.~9{Y4FrD8R,@̯hYIK4L!J()'[xn!==*l~%OY%D^ط) &Va8ud΅y"X/: Tcn30p]۬(S^ *RewBN+O*Ԣ*X X* ȎWYh7J@ 8IU@"@9 [_j2AuhץSI*i[I>mBDJvj J3DbF!`_1 %UL*ʪɛƳ$՜aj,D gIENDB`TreeLine-3.2.1/icons/toolbar/32x32/dataflatcategory.png000066400000000000000000000110171506556630100226150ustar00rootroot00000000000000PNG  IHDR szz pHYs  ~ OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_F*IDATxڼkl3; 0cc"$)mb i+Z4qy|hӨ-AMJT QUJ R"% 4m"bIJa1f5~ݝ)Ch>̜9ιWBPZV{*Kb|ҲNVUsG1@bqTz*?|LR tm'eUد1U% ୪z* tCuO=JOEMDJ*^TuoUe `뇅ߚÍҝpT]k14)n5eG иo㕝0>q&S`tKׅ?ȞM ~ $ӿZ3n۾CۉQB IgU4G?^b~7)9\2׽b{Ɯ'Ϝ'hn"dmS A*Q,oڽ:3r;}Mt-($h ߝ@;&=N?yBk l- fN30JTpWYۖ ޺mS}'in8K]K]Ya)-\|tOkFXhܕ-Ha5ֿ2tM |1σìtxVZhdigZ_{xqv=%2 ZxN<渿n\BFPls8#ϼwlnԕ(4__ȺV8¼y}42LI~lH(Iˆ@x˝t]ja_l%)4ijY-j!!%y*lDg__XAz"T } 5Ӛ; ]\W{#).Pnb[|,6,v`cFjzcb1D(DM>:iqs|rfi32aPDTc2Aߥ;t]\/BA"v ig I%!-wH!@tITY׵UIυ ,5Xٝ؝l22P[?F70ӊ+].jQcင$hILr2:_UհlN}R_[CJeKnoQ2 oܸ񉜜N@Q3G hoeqՖ QT ԈՄ[jͪe˖YE)wnyyy GlWƆ $Aʕ ZEFc|Y9asBu5h)ȩ#Ì=}>_5p6(X=1͡g2O2t\H߾X}sO x=1SIENDB`TreeLine-3.2.1/icons/toolbar/32x32/datanodetype.png000066400000000000000000000042211506556630100217570ustar00rootroot00000000000000PNG  IHDR szzXIDATxڵ lǿid !QVjt*]JC&Vh;eղi+Z6 nPƳXJ $- l'~ﹿ{ؔeY=QYzb#sUGKvz:?+2|+Re[nƻ/TTC*Kgd͎HK@]*xSlRLfs@ǝkf,ZO\ oKn&H²j ,J/B%s m2(whx(eTEWU(^%0 jcIA?Qn{<#f{`o0`rL= ~׺K ܂!%O/fc'ܔD1~H~p`32KV\mmc9R'2gM|q.?( 覸W\I p;HsqC3UnRWQ"R\͗0$glǮ>&=:v4^gs'dN, @7pWU)ۇ&"gي//+Сa央Xسyf{*c/ۂ5'aК?lkhH~PF ` }j/z tIPFRSKk0J#[Yû!ȳqͮ8׶Jiތ"|5A'qhwm|О\4%,9  LpDެ.ۨh[ dmd/I8Z\|YExYڛez?O7 W6mUPB!D5aBƼ8qF{pd x@I҆‚mq oTu:rfE%*[T|:Yƕ)fh57{ BҍJǮqTxBM=;=&ծUku)8%ӲȢ z[]@e}M: o}AT|Za梬vܑ3+ytldxi2iv&!%2xڤ$"C!0JJAq:߃7:+#$0fi \u3j6$^3mkE*ZXMٰHEx"/0(~\U6#hK;GKФ6QYQ:x -pVӬlKkz7J>R_qx0E"HP_G>AtXi!;$=9`+5ɛ6dluM +k,&X#{'&g|BGH~ &zoZXRNfV \LHRsY *a^x-)_=EE,: `10p+rSSD,15gR zX9V p0Yx.ęa4 T3du*([O4PNÖ\CC^EP1  O8 @^lSr}5p{ g]%4t]?FDO1!m7fj69f~7iQi"q0sdD R@p8|Ʋ$qv3Gqk@D hZD4|YD2`c"W$-0B&y|yyg`Fq0+++!Fz411!:fggRzPxX,r͝ 'j9*-"HGDvu"z;ֶ',`GRYPJܻ{ "/9nckDz0/CdjZm(NR)%7NN{KD^bO]׽Lji"z-\̗9g8i< #"DD8GbBڎGJ0P&9'|9JH8>HRHSJM'5 Wf>8΅q;@D7"d'| Uf.0b}fL߯G_`6333\\\ùf &wv6m[1v< fP)_IENDB`TreeLine-3.2.1/icons/toolbar/32x32/datasortnodes.png000066400000000000000000000011521506556630100221500ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  ~tIME ,ѝIDATx׻kTAƠh#jL[}lH:! 6X 6/BPDA,D++ ؈X| kqgٛ|3w朙:mQ!'['.hV'Hɉ]"ޤO @TZW!tON9( I&8q[|QF0_6^ i#-:RZ[hiJw<*>0qŏķXƹ f`.9_kx0A=KK=0c6Y^iJ:aTl]@d%o>%.fcCe ؎'+\Mx' 7k[s~7f}Q)EditYrMR!;F Rq Npm$X@d)0%])`2ޓr >ddo~YXw d*~KQCѢ~:Ϗ~d*/HtEIENDB`TreeLine-3.2.1/icons/toolbar/32x32/dataswapcategory.png000066400000000000000000000120111506556630100226340ustar00rootroot00000000000000PNG  IHDR szz pHYs  ~ OiCCPPhotoshop ICC profilexڝSgTS=BKKoR RB&*! J!QEEȠQ, !{kּ> H3Q5 B.@ $pd!s#~<<+"x M0B\t8K@zB@F&S`cbP-`'{[! eDh;VEX0fK9-0IWfH  0Q){`##xFW<+*x<$9E[-qWW.(I+6aa@.y24x6_-"bbϫp@t~,/;m%h^ uf@Wp~<5j>{-]cK'Xto(hw?G%fIq^D$.Tʳ?D*A, `6B$BB dr`)B(Ͱ*`/@4Qhp.U=pa( Aa!ڈbX#!H$ ɈQ"K5H1RT UH=r9\F;2G1Q= C7F dt1r=6Ыhڏ>C03l0.B8, c˱" VcϱwE 6wB aAHXLXNH $4 7 Q'"K&b21XH,#/{C7$C2'ITFnR#,4H#dk9, +ȅ3![ b@qS(RjJ4e2AURݨT5ZBRQ4u9̓IKhhitݕNWGw Ljg(gwLӋT071oUX**| J&*/Tު UUT^S}FU3S ԖUPSSg;goT?~YYLOCQ_ cx,!k u5&|v*=9C3J3WRf?qtN (~))4L1e\kXHQG6EYAJ'\'GgSSݧ M=:.kDwn^Loy}/TmG X $ <5qo</QC]@Caaᄑ.ȽJtq]zۯ6iܟ4)Y3sCQ? 0k߬~OCOg#/c/Wװwa>>r><72Y_7ȷOo_C#dz%gA[z|!?:eAAA!h쐭!ΑiP~aa~ 'W?pX15wCsDDDޛg1O9-J5*>.j<74?.fYXXIlK9.*6nl {/]py.,:@LN8A*%w% yg"/6шC\*NH*Mz쑼5y$3,幄'L Lݛ:v m2=:1qB!Mggfvˬen/kY- BTZ(*geWf͉9+̳ې7ᒶKW-X潬j9(xoʿܔĹdff-[n ڴ VE/(ۻCɾUUMfeI?m]Nmq#׹=TR+Gw- 6 U#pDy  :v{vg/jBFS[b[O>zG499?rCd&ˮ/~јѡ򗓿m|x31^VwwO| (hSЧc3-gAMA|Q cHRMz%u0`:o_F $IDATxڼ{pT?M͋#y@B<*(P-؀!}G+hg:֎NFPТ@ $lB{?Dvw;199UUk5U*KPkcE@pgMUetԉ?;WUaփOcCdx\ lJ*@`#9`+{i+rur\jIW?:Ub0X PSUv/V֗?jXvo K bѺk}/JeuOX-S5U{ihi??7)qHL^9ݐ~@6jKZ oP}h63Zms'&;.ml-`/м%jK+pJO0=D$u EM̯mY_l|~6cRc3Yo@p7aF0| ʶXu/teO1g$UQͬenzk;8|N-;{פքk{i@G'NuQIZ=߆F#PuvdV.{G@4xM[OXy)Z8;ZY[;pԚnKYgN0C||Ot|ܮ'=1nHⅪ6cɿPfhY8V=w}̹bzrqhATQlߕl49QbKAZf䙑Eo|E~E$Zudt(N6 [(fXVx 6vn_ )INa;VHVFWܗ.SdkEN}c>&hOHQL__/㬠O`_cnp-y7ٖt61'$o(*C}ܛs 6\! Τ%ϝ6{YpJ$w~;a(Kn`f+HVL^t{&]7`/v:4t I8Ҝ:ob(Ĩx .OGG sZA@D4s*pu AEKAq&Niu2ߴ%ife7̴oQ$ch?)f,iN!$ AP֐ w|0*t{XSr|8ܢ`P& sG@.Og%GƪVAQAnTjd&nE+,ʾH{C ~dnp}FnfHf$B3q!?Mg{}[S>JgWw+*Mtr(:bT(0+,jXS& .-D"{mk@Th:wUVYChn@P.'Fi@.Co}47" `7Gkłp-"prKH2Ն:koL =/ EѼz &a|&AGw%/Pm{j> @ 02=Al{ACAF<CP? 9t 7&؄u;eQG@yMHKK+1YH-Tړd1&}26}ymbׁV{Bqp ||nIh&lo$vm$Dq'dOjΠ>_)t}yJz?weSzx`̚}]}?(q~_,|\T2Ž>>֍!bw%Hboع/ǟC qoF:Gx9_)ޛqQޖr?Oe/|}|w,1waxUŒ/ ,+LPkwv盾2\<}w|>~Ɗue9*So h7̕ g1q+^#ٓ/Bb|'h>P'|:+owlb̀S0s,@CVJJp[,[jz9e9,%TRJ-kVs-V{ -"ar+ZLyt0HFeFgi32l"W^ŭoӶwu\;c'riFg/5FM{]Bå|Cex&\T l,{@ڇ)ceN9H.jN6yBA!g$Z)ż arӑ!mtc;3CvLr(e(m ghu:Y[#yuGV<$yW-rrWXC A|XT| bpn`œ􂦓ollps$Xovp0]\T!pc}B3XV1,UCr5 =TvOtr EZGi"O#=":ORBqפYG]efe;cO3E13D+΄"6:tm}lܠ+[817$Q1.YZQ`=E`,)q}/*A>W< ,.GҢ>C0;u&T$2|>RrzD6'OdeƎFd'aB]2 ׮6H|]ϠƊ%t{}B_&gBQ$2^| D;drc&=]HzղF+[r[*,5*iLnVȇoGo٠dLǠ:% )w`fB ^V<#Bk&uaV]K)pG,<(p ҝxTC~TJ<8qQS5#LԌBwTZ`.rFΒ6#aVL "?X+YI_TG69+2Z&/Y) L)h#N]2+MΎ{,e-Uzݔգ$DՕ0D,;qSV܃2Gկy*\j4O^>Z^sS x CFa&+GS!(U4!DR|ԋ~O"OLLdv >BeoZ+Pj;!&l`s$Q. 5t'wgۖPb"؏xj/Rj;drK`+%" aStp" m^U @H2R{#!ySx|30548SNw-y3+yxSrH|!KJ1;ސ]=,dpN5HsҮCϕsi*U%@u# à~I"WXu.o<3jr)Oޓ}CC7gn)/El~}#p͠ٯIb¹/-KLOvT?w@wkɖ2͐k3C $i¬0RēP?ul=1ACml/7u5@Kt(< OU ~74wi)nw{ ^Xr**w(UtG%5i=nhmM$tUÆ^b=q~'9t ?\vQ:۹ﲰe/߹ujWfobKGD pHYs  tIME,:/<#eIDATXŗMl\WM졸 mLXEU Q6 +*(BHBۈ EpJCh͸LB$m96q=3{c Gyw{6###{Nf2ƘʁR jN6=?11B0)" "[XXΝ;'N````n!i6:o>ZZZ=:Mc\(QY30>ksvrcxF%ҭ9~$m{11FMh^ƯT{Cuz &HD5$g.n9(f~ }\R6V-}DHzθ=(>ϝ~y(Χaj lU $kl: X$΂o's?yߙQpl/䪚juqE"RpS{G_`s ρS#r Dfךr ,~92߼ӏ Qqܰݟ M;8Za~ljB׾|e~?^n9wJL[MWF][JOш8׾Y&+D"=QI#ĥ'eFFH)á6ͽYp'/IgzȑHoS>)-tc.; @sJnnPN8s4Fd(<' X|ZQF>_ Z2uXA\D'nvz P{j6al]'"8R 3ff޿?r90$9X'NP,@5)KR/~FD4S<55JE1/C@c|#Y`FDSXIENDB`TreeLine-3.2.1/icons/toolbar/32x32/editcopy.png000066400000000000000000000015471506556630100211260ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs   IDATXŖKLQPJmW#1JBn41>`+Ląф@ +]D" R* M{q2-0mo;D$=s{ \"l*Ώ#nI%vww}vj5f!w`3 fAa6Q[sd}ck"bdD]uՉƇo "1R,f M]@l!$cι7;[DNґaEÓ,xf%dZR:}᪃!N|Ƨ.8\0?8^!޿xcHyjab`4k5 `٦eC%;^^Q|b-`Y ywWfҵ}3r%"0̤O{sQS &0b 13q(iϚ]Y@ f@\0(KzV 0N]''6  -b-w|5q+.ۇљ|Ҳz ,q 8NMb_">@} WR5M,`  @>FK}{ B&?ijD G2ڈϤ?=lY:* NԜݥ*ۮc_me``ߋ&j̄b Z&:!+D"AE`3G:ZrΏ6k|UD,G elJ_IENDB`TreeLine-3.2.1/icons/toolbar/32x32/editcut.png000066400000000000000000000030501506556630100207360ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  IDATXkLWwfgawXAy#(gDQW4>5&jqA_D[6h4 >ښj1e=7xQU[UN:`^s Ā&۴Xv]4k2mZWm&Ëa7 ;^?d ^Q<6~\*"46*i!mKUnhBaP2tRm,4٣H@WyNXR^Hjf WQ$P# {rP)r8İj(Ro cBfH `XH=G cYL: u[-:$% =H2#c] Z+mfpZ7(ݕI{ud " rM!:K8 r^yc[˲ƣK&2yIENDB`TreeLine-3.2.1/icons/toolbar/32x32/editpaste.png000066400000000000000000000017451506556630100212700ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  IDATXMlTUЙtNLL-0FV]Uх,Q!DV$k4.LЅ .\W##&c06P7)o:m7?9{sd2iVw|i𚘚ȞUІq^ԁE!挄|(#&/G$(u~,b~ |1Hb(?͊cx e&鹴vۉ^='Ji 3SN~3IhW*V/LN@& =۞}sߩ>}p8{<%3WH $ɩ9n5 feXکxD)fnw?77"5 9(ݡ7iQPq0+xw&4Oưc K"ŷ_8=W8?wAyoFΤFYwsNΝF$5/[~N~p5ϩ EEGW(#;N-vp OѶG4NW(}}z%һup ւX[-Q\H;JݺW2giޤ_AX4=v^yv Lf0Uۮ[֞N$IUW@#lpT#)UgvuFTyjҪ<  = $b/[3`Th5. :`7`@ +P!kuV:u; e30w`=Gr{+v0ʵՊE ѲE\:QX.-9Lǿ7+?˗>:٧ v ŧ7r g/:obgOԧJQIENDB`TreeLine-3.2.1/icons/toolbar/32x32/editpasteafter.png000066400000000000000000000031041506556630100223010ustar00rootroot00000000000000PNG  IHDR szzbKGD{y pHYs  tIME  *IDATXímlSeϽ:n sf3: /4@F 8h4A?`b\|&j|C#8uFkW9~hnk7=Ϲ9?ULZ[[f*e4cݽ#WjdˊxQԆSqպJ(2|[Φ 6~E \7__V]yt@@IK˅* wOWغTD)-b=vo{l8jE-ɟXd45\dqy3J .[|mpy[ 1rO$L%, 2&8p(GFp*@ G?E)c:IHzcN "\}짌1E@WΘ4~aѿ耠EВmpjt9t=׷_tX08x@f@ ZHea94ϭ*|de4d"?ut Z3-g` Di2天3]kؿ6~9Sf޾ky5?cxg3失`mEs& oR 1 KX6֮B0{5[[UZqI` TE@F} px+Yޓ|wU>YP4h-IlB-qas#jinû` t:o#&==C qscY3ճgi&9 FhLp8h-|.Z旧4d0֭:Ό&))֥M8HD#:kitH$m`AX,-P\ybx8 (n ' M0P(p:tCT K VbM˂ y~ou7qtKa$mtH@[ֈiR<8gW][jر0 hlt:ښaĸF~i`˯3F!oV$rgkwB7=nN"$HB[ ,dg&̛ƚ)PZ m3l3ؒNb۟J)ް_xˊbh}%ny}i/:)2U1.=xZPJQ__O8NαR GzWT8ʼnh!bDqt@@}" :] 5Qв`! M#'ah+ "K$[0#F8|$W9KM`BLO/SQFHe4h$c"|䐓xq;߇DAFF©;anK bO|D' x)}WW -Ն*I<_X \|&:6vgՙ |,-uvZ{>m%vYu1+IENDB`TreeLine-3.2.1/icons/toolbar/32x32/editpastebefore.png000066400000000000000000000031751506556630100224520ustar00rootroot00000000000000PNG  IHDR szzbKGD{y pHYs  tIME $m IDATXímlW8fYYMXNmWЊX~1Z[HU uUAn6ʜnҦk$M;ߞ{~Ďq9??VhFp4tXk@_0~ ӌBwidۊPՆ$+$"Ίہ2oQJX?K#0Ems@x,s0۶N~Ƕ}r?'p O3 +fZs0<2yBӑ"!a 0}<639cffS']03o?|#gLP[nB3 hSrsCBr 5Qe?·|?{w Z- 7{{V/h.pt݇~𵻦>hAD4 ",,Ɩ[s{k^"N F?O8s5y²Y LCS}{[5Z[ 9roEVwנRB,5.ֺ5}_鯨Z׾,aiSIx^JA"iai r6fQb ;܏<|~X`T*_+EujO^oU*ז E֙whوL)ŋ'icD3צy/yk4Og5EZ_Q 6s6x| X$ X׃롹4ZțȜS[ li "̭%ыq~ݷDH&h*t\l}w)VNAK(iB)$88ķG,-ܥ("oTOEXm hpp' k _g˗ [eA/0%Gk01br͈Q+J)eK?beER,Wϵl ys|w7Ɩ%bȄZghJ`iWx#+<؋|4Ix$'>Dt3zp8NKh4J/$-7J?=5FTG{|<N'0̜7T"sfsetj-Wt.ZkO-2[w22O"mlX=ǩ#b0ƲRp4{?:Pv͟CLW-$9~(˼ '.&LI' g=cghfqiM|PbFIs]?U`@UDsalt;5^d/8yW^.=s:(Z:yv;Y47MkmWT  " c;O=1P*`ME--u];wdQ >ūٳH&tU堾Tsfyn@c(+"*<aCŒ47Yn67ӟ `dx`Vt[Q2Ƅ@Eq[b)ITJm}w;&2Z~C}|uwe":UPnh({ch(N 6ea#[,{D)97wqgԩXV@26eu;ng2Ttu[Q ׳=,.hl!ʄc0y] DgLL:(W]=EMm \|: A X~W$TU P[#]#\`j2)y}$@2>w $eQQ)e 1Hno 8p`+1 DYPVȕK^6c%l*q.GuZTctHfMjChf؎Pm]Pf9eȻ܏Ƕm1D"Z4<:o؈eYAcҗU]ݣ4 HUyHx$F21 ]<6`$1FGq,V F 72 ++&rX)7 ٿ0k|ɭ߆exm?Y2r_LZE/{y_)1K4rǎxQ| cMf&*(2|ۛݧ@-^Polw*|^/{c0it B=rTWT;׉RZ~֮p<֌Z;]U\bTrͭKV6J */\xcpO|M폅 S|%Ytv]PPez* \8|Owe œ&oa2ʼrMJ#|K9MS& C. ;b+~GGAK!U2ck;m`ي߲: $ADm‘Q9!w[.U<&"tqJxtFv}=Z3-㧧'DiRh,xW~,uZ5ZAKK 9ASfں+.k>`ȥcQ?wvg[fi@[8R 1[[A]k޻ G8³vӖ]N(JA람َ>,ų/ȫ̥WP?a%CȔR|Cig~\k]Z۰ᑇ?'&G fqFfH,#M4@43-.˅ւiAyJCzCq䘔35`2Ftj5HnZVXMiEZ-}q 0F.CKiBiB)eYt5GT [ vbM xz9[[v՗Y\wC?e$ct H@6ֈiR{|c^Q˫!fSŲ\hg^mO0b韓;ei+k& 87+WS5ƤwBNm,1!bLO]H4(5L.ƞ S4ε_+.Mt;^:+x|zIl;RIЬP"nNLXr<-(%'X)[Lv+cU "5Dqt@@/ :] 5Qд\B$ޘa(W2'YR}^1$wϏWegd&w4n,;/Rgz:Pi 4u3ps(}^Lć3 >$ 2& !l- 2_扰`V6@@K oa6TIbo p@u!2i8{RY^n%:E##Y<`)(G/n\[e IENDB`TreeLine-3.2.1/icons/toolbar/32x32/editpasteclonebefore.png000066400000000000000000000031741506556630100234720ustar00rootroot00000000000000PNG  IHDR szzbKGD{y pHYs  tIME ))k IDATXílg?{^ztܖv#83#q[?4Ncqud11 HdjST`a$6e-+ e?n}[zm{o $9ϓyimmmVgB޷W*Ӭv^.F b8%[L]{U㭨U4~*Q/|=d$`֪́dvi*tvq=כp8վR9|T\Lݧƈo_-6漻Y!&;W-gNX!>*ίܺy};͕N`> a&o O$R()ĆOeYYj߁3\cI}EW`ėD8{>CIC7Ȍ1v8Fn XK+C7<\`e1b 4?4̩˄'<=-q)X`Q!Bjkkmeddd^SD`eq>_ր@DJdX,㏷w*񸃪PZQ("O'*ױ%Ҿ #gPM1N#MP c ^s|cI⊒_oε!ד7 )!`⺸"*КqY|._&srrF%iQ"ĈY$/ouI"Q7e Fs!Hjc]֔Ga0oΞԗu&4U~Fïˏg1=7(Uk^&IwASq*}&Ok,*RztK9M4;WS rp7$cULibiL=l[cݪJ;*]7F Q& +@5e&Tc PH$21ͱ`uy34ĉKLMlgq(?+ SA 4޻u&Ӳ,u@+U y|kal,mi~mLS!NޏGIWd +j)Ĥ5%TS?x~9{N3v 3` LL‰E3anWx&m5lݾS'?,@\}*~[Feonx,<Yy`Eus]ݩߜX('׻8soE+Y](jIENDB`TreeLine-3.2.1/icons/toolbar/32x32/editpasteclonechild.png000066400000000000000000000027661506556630100233210ustar00rootroot00000000000000PNG  IHDR szzbKGD{y pHYs  tIME *6IDATXíkleۮ-حC d#L%B/L-f1 e1D  xCb0TD 6dJv|ۧae7u~uc?'x^!y>;рaX1f֢V+EW|Ϫ[n `6Q ]{݁z±pX .0h~iܱIScD~ h;gJs0k v.ɂNGj^9o~z~ol؀hPD4H!иEme7gE˖J%p욣C!sAECߕ]S Li 73Gh!Դ&a`_>s()#Ԛ/}cPD\ن-D=Vns9( d4N<=n'f)"B6!tl>?p0Vg~[< )lyϳ0Ķm{E2+* 5^&ܜ5ݲQbEbIZZ\9x/c eS S}muUoH&mR)!7G2ee u{w޿O.9* C[U6~`l߾P(g9sǐZϥw ΞD(AHM:׸tpX,Ŵi,Z|*)W |z%,L^=V,Tӌ1(~<ˢ=*7"DGb$#;+ 'Fć D\PKuoafhX1|1@0<82cI9+L\YaQ^Z  IENDB`TreeLine-3.2.1/icons/toolbar/32x32/editpasteplain.png000066400000000000000000000021151506556630100223040ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME --vIDATXõ]LU36l׶J1Ei| y^Lć-oM4јD|PS51$X*_.,,00 ;.0I{?{GcXO)KGù>bow`d|]! #YƠ mv:D/Iu w@:*фP怫'ϖUVB%%D~x\uujD)U15MS"/_ p1֒ʚ*֒+E#TWiiE~4XH,[?9 5,EI& J6#3H|6aڪ\EӘJp1wbs'fM>c qMB랲ʙ;P"q`Ě9e ba9k J%-:c_v5c\nm;곧ffnd 67wc{v~<\\v6 J<և׊9"HT*1AW5{}:\p/uw6ܙՖ!3Rl9Z-,jpOš=}C]^)$E[CqT Pp3ef@vwyM1'LBp`ʹݥAn;ϛEDfwRzhΐW "6!huh(5p,K $ot@cW=60(i%N{Wn|t";p .q0rMB M,J .ӝn2P:`qF R$l:sU+9u@_/0+HűwNn@i<揩%0)q)ՅVXM.y]O}XҵFh| hbazοMb}\)+W B |?+ܼ2bMSIENDB`TreeLine-3.2.1/icons/toolbar/32x32/editredo.png000066400000000000000000000022241506556630100210760ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  ~tIME 3-T>6!IDATx]h[e$M6m&uVp8a9X 2]ɠs Sex0A&j729MүIs;Mc`@xHs7]^"k@[׉Xx^ c4TT{P}MW^'^uNU3-.G_)&>.c~de/CLdU.G ~(dp9D/6@ɖE?:ġn'ז"Oc||)@@yX ꑟRs5\bx4(I9܅fJ.Jܮ%!E/CzdX|% ljn@5ҧ>}`r< Ȳk{W '߯F D˛?_׳hpNRXO~ p≛l}Pޑq]q]X7EJ~0A߽(bsόhkWQ.1@{MM;YdM[y)CH>o.׏@`_CM$2,ilwOp#\3(=ç^oRGUVyt*wu2}rZ[TTx}x)Csk8Y2m+,+m7H'ҡxs 밐O>),&gCW(,t*XO ![V@X @}G;-~G$H8Lǹ # BZ/ O@&3qEvtd̀9 bp1S-f@2ȡ ^7merڰa)=4㓮Kv"k Jm}`fG;Esf:޷l#taPBx  GP=xz]vr}JcC=F"6 > 7mAJH–eJ#3qGճ`)wKB4ilA݂i IvC, ?0< )Ob\){Rt"]L6,z@/ t5̴T2QW8BAQTB<SgeۙI lDd]9ވ, 2wrºfҠB6)K$=!GԼZ` k+_RzRDZ3H}+{{8pHZz&\X@ 2a'`_jΎ2F[,k[yXƼC u"gꊾdj7 Ή26IENDB`TreeLine-3.2.1/icons/toolbar/32x32/fileexport.png000066400000000000000000000017371506556630100214700ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME +lIDATXŗOh#eLff۴P 桺T/E"բ ' TzZa*PaW=Tm-vC%ۦ4Ӳ/|x8F+SU!!PJ333_MOOydzRV+yl6K>V=;?? R8!x7Ǐ@k"Vje``&&&#7$L\.G:+ cb3 dxx!===r9l&T*qe8ܥ)L&3ncLl]A@w t'lێք'j'Zi:)ROD{V+aDWzkz$+>,%-7O@H%֚[ zt~OYRGwpee%~W*Xnۙ CʛXFECỵ`xèڍ[^Ƀi,;rI{=5|SR6D)Ⲿ+]{3v%52TGN#%kk[ ;>2 Pݖ$Y^[Zr焑XnmuXbRJw,J:@`-;3ŭ?62xdk\iFQ plGXXX\cOD?;"Hѹ"S9FFFġa'0@nk|< sD`fGpz]J5RX,RmXu"ϋŢPJe}߯,---&w}Kf0͆j~[@jw#oK숾fR}KƘƘQk%NVQ97 vG?Ә9kIENDB`TreeLine-3.2.1/icons/toolbar/32x32/fileimport.png000066400000000000000000000017451506556630100214600ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME eirIDATXŗMh\U}͛s&KhZ1J$ " ŅYDI3Mt *f%dQٸn,-Jjd{]AR&ɛ=p{.Ϲ?8PVB6)GPT>-nNJHӔ[ڜRҍ(㬥#!DW!8t X,F2u]Z6RkA$B8J֖w bxT*6L4d2 J<<;0gY;V"#Rt],%6ڹ_R yA&;|'Ў/gVYv\O4cfMh\~#&'^=̉zqQ}SSZuC:T | KYEhz׹{KMCR mLf#{ФjhMR;|r{F hBFo__Ȝx@ "Z#~rcMMMVC߯5.<;'ޮ] ;Ɠ,߰m{_ʊzِR[w[X}!p^SzO`7RZ@EJLV o*+ٿHIp053IENDB`TreeLine-3.2.1/icons/toolbar/32x32/filenew.png000066400000000000000000000025311506556630100207310ustar00rootroot00000000000000PNG  IHDR szzsBIT|dtEXtSoftwarewww.inkscape.org<IDATX[lTE9le[mKm,h0Q016&WMPyE>XtEC %.[ -TzK9g|8K[ڦ;33GhdQLk0hWG5+HQPEвL5CC,^CV[乮|mxO8ArJ!@J1-)%H |>A%Ykbn 42SI%CMmj&Yf 4 nxefP͚/Ss<7M0~Y+J6űPS[|n+HO !> ~,1)έ+FPS[֢K!L~22 Y~%UZPS[1R94ݡ]p5()h9W?[*Er`6˳y;q#Ük?Wg@2(Mp]/D.oK+H'=b[+(gb@;+ʋy2137&~b 7h3o> @BB A?|߿Lg(:(盶{|޷?| 5 y_m_?1@kC<4Pw Q`#dV/ vPΓz\⹤IXTP7IANǏ ?.&& o<FFT $>'߀A?C=>(Eow[[+0ؘ+;޿pc#Wna}(9$\g'A\ ?͛ 1F 7ᅨGQ5@Ϡ@ @!>=%K#yCM_$x>~x4 4-@,D?sxyH˭W~ar ǧ l, ~KxZno_ H@~}ȐoM<r@CAEN~gзaP P6{ OL e o0I1dEj3| I /Nj2|q p6cNtBʇD0 eG/1k2dGk3=+lp,Xz& ܿv hx2,-ga=AA(˂gdge`x ,uu!c71`(CW >f |bbecOX^|_@>C=oO3\=r+/^2dr((GJ쵻14F)1Ug| fP%_@f2|\O_gx? ?eÏo~WwO1{_30ga`$x@D Bh~o >B "P B w>|¿`   /0H~AJ@vn?0;B@O|E ȹ'{`pH(:0?+`!? `/|ңw ^-XJ@ 7$1_O?1| /# Ç@%Ba0Ó/ ` SS023 ?`_C踗20rr10:?7zu +O | 19@_ #$ 030~3<}򙁓 )2P (/!O ,#C' u_4?8a0ky1 ?@dBA * yyC2x(@pϩODÈ F`T1[;L@&&`EQ@*ξÏ@׽Y @Ag3$a/!l!n#,e!?|cq V!]gE3p!)Sgf8x @ν r R;L"D '0?~1|HT5}c`vШ/b{`!\~Z72C Zf/0c`7$A\C񿟯o~)@twɓL&vM2/WtlO g/^.RJGh.1\re˗o^~ù{g}aŋS=fB85C !=z>;rvv֍zܜ{ w0@;!(JyXT2Wo۶] A:v;X]u;\Fqb㠔yw*JN8ǻQ8N>=z4 ё?cc0:C033^p!^˥QJa) eòdhzeЫ7±gϞe~u 6_5=Gg.HuE"Rz.A10ƠD 9` "@uYg;(8A;s :dXd-T*}YF`P˗KKKR~wFWoŎ "@זDW P1A<7]h#Tl˲ ֎^tSB ZĄ Ūu pTz$R倆3 Z S"籹ޏ>wM;0ofػϔoa | ֭[fAVY 0JXA@C`PϟwX)EsssCOb~@ˁ n7GJ ōo_a!RNRضݐkPrX"6(泘`x.(9>>΋U~ffƿv 45o#ΝYE<veD7iիW]ye[:K .]Bݼy弱ښwƍb67::Z\YY_^Hquu4<<' ²v7}&Խ{n߿]\\^\\raaӧO[ɓ'5 8W@Vjg^""$E1®"m@ց=@h@ ׯ{>bIENDB`TreeLine-3.2.1/icons/toolbar/32x32/fileprint.png000066400000000000000000000031411506556630100212720ustar00rootroot00000000000000PNG  IHDR szz(IDATXoT?3;{z fmcŘF*$RpdPyh$KP*RRE?* D$ * }hpxpmjl` 6e׻{;3}p QHWgf>9g~+XN)N{.vݾ=:pاS E֝;li|j;kb|IJL1m-X[q_\( Q|n XkZ 0Ƭn`/`ioEhT4{0 v^r ԫ`6,<7Zc:E; uc1vepͬw)~ة~w3` +h&RDgg'Dⷞz/\P~#Gth{vln~tXk0 >}7o\봷wܻz#~}sDH)rcCQhJ\KC\B\XҢ%i9hiifeL&c```H=zwuX*G1y=G".I(I".HU+k"c BCY*Yoٸ{ٴ)%BO~q 818'KCԒ (d3 -TYiK![p/w]7|MZZ}}"b60_싌%B!|`sWI*mX N̲۷K}x0~R- }(PqcBsB!}}kVU+Tʄa@aXu|ٹu.:+"JeL !*;UZ\ɓ,Ljltt3gΰaи >-łd2CqK)|tt:˚e]d%u[wٳgona쁱mvjkISukkmRp@7͍(%rݿ ŋDSSsd5׻A۶22rrYuʕz.dݳgOR[Z:y症vھYh8uOs#쿁I{*/՘1Ɔad}?Ţof X]]_dQM?V9{ $H$7hm=V>qRwm( <55ہ*`Qa_YV IENDB`TreeLine-3.2.1/icons/toolbar/32x32/fileprintpdf.png000066400000000000000000000024351506556630100217710ustar00rootroot00000000000000PNG  IHDR szzIDATx^]le̖QRKE/HR&%l5DQoA ܩ+Fbu!k H($!!haiJݙa Oٓs~d1+B]vm팁l+V71M͗.]X{[GGG!XqH)))! 0 @OOtDwvv۷/S @b$PJmlF\TZ PJΝ@kgp/0P@RɢGS0_@d65K:}.hjjcǎLXRZP hFbs9.Ӣ!?lٲ$ \cP__Ot{MLD׵ P%A8}J+Ĉ͕BpxP?JB ш̵!. #W%P 14fB ) +V^gF>$52]`2S(@K(8;1 ={qֽE+ɀ0֑01(%o <1?} CmOa+CBܔ e[cGlߍHEx ^+̏?mᧈG@hP~BMY6Xh~*+e `4Hl0 r& ^}1sO#[pY &%oƁdgW/!z\Tp4|s"(Ӥۊ qL@ݤvoANgt>QXB~qmıl6& CfFugDus%K}HpIpXuq=oDS㘍6>yzQ][ C"DJi`h[WĔS'PW7k_cS8;17|O8p m6%m+ě5 +IM߬8T}6ZgҿrLWF'C$'wh$}P2@M6Cz4Z x&*O u TB[a/f́$&9} ּ%QQ@tdt~?66E>H6f5+v!=Y9y;0m ]dwDaAS)0~~B@:ڄ11qb U`e>`p[akRIENDB`TreeLine-3.2.1/icons/toolbar/32x32/fileprintpreview.png000066400000000000000000000042521506556630100227000ustar00rootroot00000000000000PNG  IHDR szz pHYs  gAMA|Q cHRMz%u0`:o_F IDATxb? ܹQ\<9z *ǯ? ~a÷}: P\H cXvR@,$.^g/zAWG 3b&F ff&‹{$FQ@0fZ L3o3% &DtbA"F@ 3p20s3q33 -]1QQ ?0|'0Ү4+;01fx+/`E.1I%i2C+qkY8XXXXX@_}vAV87@ 3\ | \< @o߿3 013o`[w1 ӧ K'46Qa)s1!6.e@?1O`VÇ'|/# ##4@xC  1+0 h t4_#80mp A 0cQ+ j!+>|@ZAfa?+lr_Cp]])*``^ !g[yt 9؁ 033×A:g L@Xsp(LtR \@0s0ށ`@G0TDK_@o>2pKTV<~2&+DXyq? `0 > +,_u VJT? ;; #`X|`_?+E3+0{2s!@8n|ax5@{6PbfFH _>3e: :@VN\{/$ʠ" \2?8! %_b?!04ٔ3`t0KJB PTbac#Ëg9~r22n` r3=fï| 8f Bb4@8Vp2DG{3t/e~,6/rnv% .>\|o3B|ڒ aT$\p~F&7{Y)A#@66h#Зi͋o ߟ?BzXg > DGO8AMS ogxt!_eP"< ,z ߾f? ,=]\ +ík8p$?8?77p_d`ëԴ32ebZt' p5* j>~py/O`i|IV^ACK /Oa`q aum-ó>ݪMtU`!?#Y r<vk\~tOn={mǂշm4FxmT6bRBw+/x'~'>m 9^3>m4ZQTfgOKǞy¶m;ZuIZ6C7ڠh_cYDcWfgf.]Տ=Hu㭌Zkh D T.8FN_plǎ4cо"}ڂ(bN"dxxڻo߷:=&#A% 3ww6-! eY|X4N&2S;uY8l,PO,R `'M>?Ύ3#G,3w4kA6ɛ1ZJ.gaaCD΂15v %Y~O-U!F%xn3gWg'DtK'No0@ftt>DC!Q lxt:x<le@y ,C:3wU6i!C̃"1@Zk vjoH!BBHݹ[Gﮐ.3:ڋ~UB@Bpm06ђ[527:H1n0qJHi!%R6!Mc}pDEwf5wm0W),*`!Ԅ![}t[wq~ﭳZ= @"g{f6t!DH2v#oAGg~zfK`%j?L6w?.""q,[s6Ph1k.}v߸7C=u煚X\\j KK;q4%>.ܼB]s{qW1D[ɚbܪot9]WHg,e2#x[g5#v ;=l+;9؏kE*µqWWpM'ZxJvsr^K3X46U#igqRT* EѢBQ_kxz.t%tEXtdate:create2012-10-06T18:48:40+02:00(%tEXtdate:modify2010-11-14T05:57:36+01:001q=4tEXtLicensehttp://creativecommons.org/licenses/GPL/2.0/ljtEXtSoftwarewww.inkscape.org<tEXtSourceGNOME Icon Theme&i tEXtSource_URLhttp://art.gnome.org/2yIENDB`TreeLine-3.2.1/icons/toolbar/32x32/fileproperties.png000066400000000000000000000023001506556630100223260ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  bIDATXŗNXuH v T6Rd>ˬF#t1̦b7@ꢓBREMAUAq;vb'a5G\{wρYׯ_۷ׯ+o޼ ݻwx1ƕRcLn]k֚8Zk1ZklVQKzjŋ61l۞:eeY)Dߎptt}a 'ضmqLEcRJO3`YZJOhCA}zWp84Zdss~,kl2)b|WPɳ_jhVbfm/ 9{e+b< dGJ)rּߞ.[[[lllzA:Nd1777'2"ٳgc㘻;6gggS݋˲<!D.d j5 8Bpqq.N rU @k]mjF#׆0Ii#DׯH)IfD`0&}qqAZVzEU0qO)&ZfTc }R)08e!A>yH)B qlf0j:L{v:(Ð%ω8q{TUvvv H nllZj<~nKc}zNFkc$".FcaĩRF r\4C&a0 3P6Fa&vhG!( T)feH^^^fwwJ2"9"$X.8>IJ,>}ϟLB9) 3P( 1xǓ'O\XT!d,juzb|"V~P& kkk]pǏá԰1&]QO ʇ~,GGG?۶X5hL1(dD@%ծkO0}Ao= +6 f583FIENDB`TreeLine-3.2.1/icons/toolbar/32x32/filequit.png000066400000000000000000000031121506556630100211160ustar00rootroot00000000000000PNG  IHDR szzgAMA abKGD pHYs )ItIME CJIDATxŗmϙ{U^UR]hZ &,@# ZOY PZRI h"RCT$mn\5uwwvWo{̜;slB syM5o2pp}jJ5vէ3{Jf5֠528hkA;hu68s~޺c;MlM14&dZtx!˜@Y7x-ۙa #o<PH褘ː?GyɅ{O<ǹ矤ϹP 4^Dm?:~9c>}w/O.D"k ^OS ]q@SF3L ڬBH<$\1?[m.\/GDW]ی^&neW{y5 }OѮvP_dڗٓ"e&ۇ/|l -(PTO])b6SpX(Q1$fn;5ZtE^-B^%".\YSWŗOfRݬy i߅+=.P;R1t>PI'(2#_-@7gf‡v,m9"a+[T\u\!p湊?ڽ/Tj\ElJO7| P.eU/-@]:Lk__5~1 ^ɛW |կjy{G MB mA,p+ϓ<.M?o0?DhlYBjFv) wFF~Tg{,WR~I"m#\Y1)#,{s/D+N] b2t9|f*S4,aM4,]啢@>>< 0nSj8vJwӊ6:h_709| u⭊z"?OϧG;6Ja"ETXq,>r;sEq1۵IJEͱۆVG B)0nswl|IT;Q@}Ӛ]c;5}v{]֔ ˣf'=^Ny<\^),IENDB`TreeLine-3.2.1/icons/toolbar/32x32/filesave.png000066400000000000000000000025041506556630100210760ustar00rootroot00000000000000PNG  IHDR szzgAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?@bb`@bAX߿0ϟ@ FШ?`5U #w.Ɉn@8`m1AFB,~M2$r ~fpr.oo#7o?E8ԿARTFp+280HJ|5`pZn.v#yA>.~.Լ_~1&;bAW90 )& ry'Z=8$Ju7觏tj@!(P ͘A_S<$;o2&D 0!rX@]Yyܯ^}` @G@8*^4' > _&?r \A;Q !ѠtW_" 0Pri 0.9_|c$3ߘ!@Q(/0 n1@w@gXDXӿVFVvfF.Vf%" PK' Kf9( \r o"cHQq_$=C [^0 BXkJP(@a?H R F`D {@5~ǐ/ ¼@ox `9w`EjAG98,vF"*(@e,֬p%JHP, T2?xars!?PAB'@PaT@oC* >FNp(#CȆ"!i l0#3A}c``c?C2`QBq}+pb{Fky^??ڦ F 10Hp7@ |]7PJ s @7w@p RIENDB`TreeLine-3.2.1/icons/toolbar/32x32/filesaveas.png000066400000000000000000000040251506556630100214220ustar00rootroot00000000000000PNG  IHDR szzgAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxb?5)ՙ~}x3e7~^?wgOH/@Q2@vCO/@Ba#_FF?1AՀhY x𥜁V?O{ΧA@_> cK\E VOdP2p%0~+ #.o~O?0od``e`ge8C_fe``:rn>0ܔgpa j PZn.v#yA>.~.ySho@5L nc+&Q@,Z @6 0H 0>00lc`dd`xL _f ԇJHB Q~ @^fx ho?]8j3k1?/``VZh9ec`&LO݋>W~3+Aâpjs@P'P`xx ×}k@f:_p"T?PAA<Ǡ|"0 v 1%Û}~.7~b=8*;Q F+Ơo Lt@YvfvPrx@AB ,BPII|߄d 7$ @1|L= 2 ˿Cх+ 9>[ o`T;ѐv @,a /`I/?X &@` XN=bg`Y Wh 1!)A k-KA߀Eϟ}C 4?/+dy%f<3k=Pt1aNb 7`!1p=bl,~}}z@C3lƏ??H Rp9}@)? ~F0 r_~@a >" }ǐNrPe`,r|:XF +ý.J2|q`22tڮbՂ ?~f&ʿ( 00F]pZx:s%.[فY(8 ( @7x$(03]6 0:ñ^d3R l_p=, 8Pp} Xu0QJc'RT,_Yhod8̟JŠ2\V&@.}2(2ppY/Y Ь )x  :8[< 2~660\l?h-ήK17?_C *:(q'Bb׿> @XZ% _R UD!Jο(YX,02 ×  @0dO#$ ,~h3 eOp,%A W&` ~H !3N/`{O#(1޽{)|D~$Ty__We\8@10Hp7=x0lt/@Ճ::p ZSr@11 0w@{()IENDB`TreeLine-3.2.1/icons/toolbar/32x32/formatboldfont.png000066400000000000000000000025271506556630100223250ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  IDATXŗklSeǟsov]/0&lLA2DW)nU~j5ht?H 1QH`^l&R.9vkwm=}['99}w=5{~tҲH(&>7dHFA( XyȀ>9 ~|1vIz0f+'7jb c5K̒~aLooog&_HRB/z^[QM%[v'(@ፐsDFiT«͛+4 fz4ҭl(]zɠ~0F#Z @u͚ E`cc=SU o:7~uLM,-i'O͟z_U_ŏ;\{<-0ח2v2ri%.c-dc^Wĉ1-}`9pZREȼG{[\.E29Ze4}6g<׏{T%;r:lɁǛp/768nemmr;.[܂ԺDXZ/F2U ꬗e 3eʶŒ@# sI֯i@@ ++Ȋ-)2nٹ{}` `!xbhA+VV+/|ց߆dV'zuVA,*˂A\/K>H^KKK*=VVo.O%í?x珗t[06MQ}`_߼y>]oAssmVv?8rۂZo[u[:LWsCw= !9Tind׊ B z4m*HP8sU(آcdZ_30+A[ň(631s,Je@'oOUj]wn@3P4L̹Tk믟\ݰk-ոJP@ھZn7;njD$ynaAE˻+4|Y§P}9_NP!0'( C_!FQk98`$RriaKn`1qmqugKe& itdk@3)K$ۆ‘oYJznf &mha?V90M"K'} 0 -?D/ڱIENDB`TreeLine-3.2.1/icons/toolbar/32x32/formatclearformat.png000066400000000000000000000031221506556630100230050ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  IDATXŖil\W͛7f8nJqKpEi!$"@ >P H4R#B+{L-PA uB!c&Vǩxx<˛._fe Y8_^{s=3'ILN|_hC&ߺ-FH~OY߼p E]qߣ_duG "\FEjd+푅J'731} ^~tЁ# ;)"AO0WuI$̩&p#BM0o^MdEyc#u[P~oOQzv~n  `ó}P-G(YExa[}Vj_P\G7~d_MmqZ֦4\κюGiuqg`4&z,{b0U2L{?__p7R͵-Z0G>x?|(+0r&G~,.Ycހ^גܻFri':Ыl<9`DsK{h|,HXz[7vIW~"Hr*q %AT[þ-}[Zճ88t{s*&`o!kU6>"`PSot=ݿo lk4X}_Ba\,&(dp]C5 7xþ^pY3~ b"X:Ev ̓>B&" ^ pfNaNL z Ypv_p1o"#ڢ nfϓ47㈷BP(dS*Lj$' מ Xd?>4rhG~9 lzR7-vJ/Ŗj :Nヘz԰x5_"OW'fj\H5r9QX"B p2qq7>L&G(kjZ/v*.ӌJ1EVvhR҉#DRHKX1k+<鑝m{:@;0"y>i9<0t@4cY>i (fZ/} E9#;st2]W{|0*UF^CO9p1ThY-=`OGS`Vf”vJu*y>}U * gVWT rpY 1h"fIENDB`TreeLine-3.2.1/icons/toolbar/32x32/formatextlink.png000066400000000000000000000123711506556630100221720ustar00rootroot00000000000000PNG  IHDR szz pHYs   iCCPPhotoshop ICC profilexڍVwPӉ_zP#UDt j1DTDiJ( *"X(F@QAQ)*E.Q޻7׷. N d8Z=>@@D` l#S?d:5dZ7\&}j!>hko[@O & tPb8;<o?JnpȦLs`nč2=h>K g'H,e ܉KwBgx: &l,.`-^)b׊TQFğ3BP87h)g-,,'8DDooY&'"N~#K2G*^:V,k-$-?и3W1TIO_gW!UE9ZuƢfVNa]7=~V'u65h2d)}12#Iu fO}- Ee崕Uմ5eY[+B;W&{ }b89Ӣˬ5wn^ށ> w(jW=˩Ma&ttd-|菈c#_=y=u1togn݈/8{9!܅IqIRSi/RҼ2gfg쾤vY\dUk  ypbK% eS7'o|Jֽ%y5F= #׻4X?2|d[yZP,`[6v/ʯ^tһRTujO{ax@`ѯFF׿loȌlBRֲ-uE6 . ! nH2@9"QPmy$}݀^`0):8(I*XI6ۆ]ihQN)N?".yPjUns4<k%k*ܓWiPfCQCs# H:j4?LLBLn H4R)4),Ѭ\׼|Ƃlon* >~GSNY7gWw/_]A!Ũޡ1H3рHh gbbmOWr?!bZQ7> 3vw浮Bz2ΛշU4U2dI5z8_UM^-g-[GOQZ]Ǟޙ0S ׆>W~n>>>ɞJ:{s^cwia9iEfq݇ظwh,@NCce|z<  \Ѐ> h=B")Fqbt>Ɗ5sr8 q"z LVy)wP~vgrjF]G\~ \&fzFm޸vdđ!T6;|GYTĉS+g%jNȆ_Er ̽:GoxJ+mŻ7}|=]6{)iy|U|]p0H.#G^Qt4)ƢsgTp'^:,.]M@Kv'`eMzfvY=yOfH",ڭemS( wenXe%yjtx6rq餸$Ԋt-y 4Jʧ*k>2|znБ-]臇c_M~yW ~ (=]\&1%B to fa H-m[{Ŵ$!á$Iڝex4ojeV!1޹ĵmS[דK4qfO2-$R?ppلk^ \J[vIfUEKr+nW㻯WC-zdrɚh ~1* U|1hg(׷~4ǵ56`-ɔH 125ďAH` D@P! @ ! ?S̀H&) ftjъF٥DTWU+ (~ױ$EgAMAhV cHRMms[+|(F4|p tIDATxڤWk\e~}gΜ3ss۝eZVJ-"^((("1DD_PIH@L XnKٺmfٝ˹~?zݪhN{Nry}ٿ?!% ~ÔOrrΏB`@뮳FGGߏZL L0|sp8%Yݾ}qq۶B.p,S*@ eJpX,LedYLJ'&&~9_0q zK)K c2\EVmB" \nĉۃ:뺛u]ZSSКMlڴ MB)m(/ O,˺>I9B0;;$)_n#MD>X ^fsc4e@$LMf8 W@ a,|^o0k'( iBfffz80 `)Bȁx<#V E4h ۶ᗤ$A7n;M7u]E7o&k֬߿5TP-Ν;#R}#t ÀiH&BU/HPGEY~p][MSHYA<Bs~vK  ѨJ}:NT*EǥP(mN.m&Tl^7dX- i>~ڵĶmhr 9!H&PUd2dzo{[ZuDkDU?P`0x_0L@<]sd2<AX@dgnnN]~=b4Ӯ[;ߝ!.<EJ%e!%4m;ceYmnuu LNh_pISD"H|LciX~9Ɂ@N0.fkjJZvvqοoY577AKk7>r)< 8XMO gch 5+(a;ѲumDIYPiKG'\\90KOA^Xq&\Il m:c sٮYt.ovz<sЃ_<8 GXgB-QysM? w {Wrǎ+)clVYEb *:ɣG]TLt"\8% ze?kv2BV_~U zt:t&EҒ[ ma)/q>CA#R\z/ҞV%yVAoeRP4E__D"KjSZ8Hjy e5 0-L„ 24D8,-I=JB !";xb}q lP+q%R%Ԋ"bH[|[y=yh4D( M# \BB޹ 0jCYelF$?l{5~ңis$ 'LJ[,˂0 SS3T:skT(&ڗ,lڼ&YXqؽH&zlҳ 355UFogVVXgz}ɓj_}gFإlApPkcďY:឵-[GFFbh4BB4z^oٳ*|5"A#t^坻Z95;"IENDB`TreeLine-3.2.1/icons/toolbar/32x32/formatfontcolor.png000066400000000000000000000022121506556630100225120ustar00rootroot00000000000000PNG  IHDR szzQIDATx^VMh\U>͛7?I!$QKB*.\t"P ٝBPQw`) B7Z J!i'R1ƌy2K0L^&=qw~yObĎ}& `"#dx^D3 A΁[.MĤtzi, J%S8Ħ)##nH>OosP1 3F&C ~F͛?RD1%{[4;82#9e0Th"jɪVϰ lkyYe@iBawݕN[%ԩ= ɴ{y@vȱ:I[,@: b>%DLK݉Б3h+ᄑz SZaP(?t$v0Z j-:j5B]< 6J5컟 {I}@K[m;7!Q2w!̬k1)r 4HPpE"1}wOA"zH&_p"T:V.<ٲ %Q"H# \.aSC'm9 T0󬽱1P_U#s.:rww )zut!Ā~@FS?c>,mxxXZD=Pu]ܭ-0 : MM/_ IENDB`TreeLine-3.2.1/icons/toolbar/32x32/formatfontsize.png000066400000000000000000000030601506556630100223500ustar00rootroot00000000000000PNG  IHDR szzIDATx{PUǿvQR"Y%! `8P2:`6Md(J( A ƈ >Q!DyXZfݙ?߽{ rc1ÙUx1gE r?!WgUPgCq⫕!_08^d vxIYho -qNoGGG Ͼ$sc6p}}=6aaя\BJR-&ޱ3@ Tx YYEo%@ KfX m}.!eywGLw{rd $%@x6H/_ pyHFC} iʳ(Qsajj_Y;}sa \I@8egP"XX>r^B GA;kd)Z*Qp^SUN ~w黨kF ޮrH*|ߤ&Lhr7ÖCX={PԬ WQV.HnW@Z} {aݬM~9l$q2+ - t]C-1I@BzVG>$&9S;tEЊ*`,Iq1SE̙O6LHIoy n"v6yG1USSIU/QOT??sl*qjPesYz?IENDB`TreeLine-3.2.1/icons/toolbar/32x32/formatintlink.png000066400000000000000000000034521506556630100221640ustar00rootroot00000000000000PNG  IHDR szzIDATx^V{lS?^:ƁJVն, 2B2:Aihk5Uh];-PtI`L}JgMJ(qk{ξ?nS&4s^ -7no7no6o}`k|L1}?鯎Mk盯~k`7硣޴F^`Yq1;J5J1iޑ}vC gZO)w rYŊG:1/ X{4cryeWse KmSYK#j`U#(n=(:Cܕ^DںkOmgٌܹ8Fgw{'@=Κ,#ż{YT`*ʷ vTln9+=ӣo]#f^mmm; P|O >|I'O3k\{buMv^0]%4!72 wcU <ں:y~ΒP)g麝ǣQ9G4UQG'5`3_֙> _RU^xyO8BQRhQq ht0(tGDTae7%NF>aPhɫZpKdNT(7GtmǏxtTU(=#M j?a`emq10# "Q^:x! z=.V|mR^̆w8IH<7o:~N>ak)Ʀo8F3ؠBX@h40KV1'J Yt 0>;p$jp=s5603eEՇD{hqaL<`L(2s"A9b+M qƮ7iIUH)*ǐ| Z/0}U +A9NTtוֹX d̘5mޒJ eDJ^]C6MBucSd ,ⰆVomb S4>o$. F#RaBdjf`@@GVTgEQ{̍CX,@腓u$&_D- @<9+]]}]n3{CM*R1Pk-8e;*aX2ͪpbx>$5c^C*-~a%0G5.`y)J qQf5V'z]j( Gu\{7:P4/sFD#g&@<1rvXS4s"Ka~8s{<)G]'`^XS|yXLT9 ^y'tQM֜be&ׯǙ2HFg)Fcjp h>My~L1xvwrv5A_T ^…NxyIENDB`TreeLine-3.2.1/icons/toolbar/32x32/formatitalicfont.png000066400000000000000000000016701506556630100226500ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  ZIDATXŗOP[nm7:6PQP"^b !y}D?_0|1N%A1x6dMprqDl]7] FNOr;< Z2xTCy[ z!q"pX `(稦yGUp֖kl*"ej'\W>Ui(.~'·]q+?VCȣ)nRPm4غ_ q 4?`;UJ&}EAb ;TiLW:#J\>7<<+`k f]mJIJ?ٮO{NǓD~yDW.ߪW`f$VNh4+lsM:PZ*=J&Bt#J67s.chI/t*jC>d泊V?%-^'q}+@OO5>~ inhh轮܇+u2; hkD+8}XNss4?4B!6k?fijT(L P{tGn`^K%FFVtNg]hqUVFK_?G*Քg_ ݞ 8IW<=n%먿HȏN!&S^/ `];8(4S IR<[#>i :J"MspAZ@՞[ժPDRBfw@v |L^ok#nkp >)RP,gLy`>Ī׷>N,*}%^woi/\r" bKGDC pHYs.#.#x?vtIME tEXtCommentCreated with GIMPWIDATXcd ?~<ի.bbbOJfff`wrrj§^KKk Lb`'ׂr3WTT,efff````ӧ8 +A89VYY!}Tq! sss`bb";kaa=ڵk92_%%kJ;11kiѼ4sq bWDD䫦2mmm[; ..N1?񣗼/dqqqqh_ӧORRRI o"MϞ=3(--"߿ub0000 a w0 oՌQ!̇ا8 L7 q''| @!~DMb'jIXv-0KOn S @Q (J5k{9 :b7Es0Rf` v1St-o"`m>D|N-ﴚjQˡE8"/|BL_%Z#8N\0ĥ:G8mَF.b.<7䅺lg7yYS)/^dp_D.ۭ^NύiW<3}z'Us"ۈHZg4+)ݤ<~IA5IENDB`TreeLine-3.2.1/icons/toolbar/32x32/helpabout.png000066400000000000000000000030501506556630100212600ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs:tEXtSoftwarewww.inkscape.org<IDATXklU3ݲݶnKˣح -c|R1!Q P!LbD >01/Pk0Q1ՂFڅ>ѝ\?,fwfM<=ϜsgF"Ο65`>P 4^b=RT_@,3߆oqU¹ZLrSk<7>xm|%?X"n6ʟ`䧆U!S" t!F{x\9}%(.{%kƝ?(6SCiü~ÿP0;6Snfq2=ϯ{9ND pu*-5Q$_@<H%{:l@Q#_úE̛n:_Wrv(3xRNN|50rwO4s1ҕ6֜|6-J^;@<4L$Z 2˒,BZy2#9Ry;oYH9b `fQ#ۉ;={XZ6#y *^JaO1Ql/C.+؂}9>;+7e_ٮJ@Yw N jmQ @& S&d3 q!n PXe,R+ J ?&±Ϸis xۍ8J\tsoiu5UUҘKWxJi&"7}VG!7M'24@dd Q1'X)CJ_u2}uqzL^a1Wʘd7ђ2 PbQJ˯կZ&S7yUD p WUUIczb=w:IENDB`TreeLine-3.2.1/icons/toolbar/32x32/helpback.png000066400000000000000000000031311506556630100210460ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs ,tIME *IMIDATxŗ][Gwڬ#.Iv6P%6{D " )/-m +CߪTBJ""%* UԈ .]lM^3<ڎl 33yhx.PGA(ٴAw|tZ},L$X@:8K&+9K?0vfx%!A"8;%>@فFj,e8O[Io%|?'EDۚR}[L'5鴿ur= yx`MFh;<[gLn.,_XWH]ɍ;vle}nvl}QZ0rh>5P!gYdT3o0ϜTU̕9u$;\Z>5s$ >v]sCӗ ~u$?]oMr(C,)<}4 ل6sZƵNG{/P(`gJfҶ[f,rP 4-^8TX:GK6a{ˀm}]abe?Z lٕWWJ咋BfF'k'Z  2H*Yb{Ӎ?/u%^XqpEjn1bfA`jM(>VOrkWWs#-h@D=@ܥ|O=ݢ<^&] "؍$ȧ"F2Ru܍9Q=FsJxnk( v CzJCz18kQuz.ς@yY@aAө>ޚCg]7hM/]ˢw%em8^.]t a 7yčv|'={-X<AVOH_(pOG_9T_(mlRT[d2f_+oO $Čvq׬D旦ow_]o\{S&Pl>] @v>G荺mF]bGv>W7t/z ɨϫ Ǘ5vE:Ϳ9*5>)Pu>>.Ĥ#DϢcQSɭ IueMx Uj_Cw 6]PD T>{M]G WK>۴X-߇m (tښk{1""{I /KP2a wjV9 az2`p6jN JWIENDB`TreeLine-3.2.1/icons/toolbar/32x32/helpbasic.png000066400000000000000000000040011506556630100212240ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  IDATX՗kUs}Ν{A!P"$5h4}#UiHڤi5ImU-M-*hP! 3 0s{~Ý id:k_cywp1f,"`06[=bT{ll5H5ƓXRQ-^͒~D_4LsZ[OUUX>f,|S3\sy,޹hf"@F!^c:YR6CUMߐBYIҙ ʜ;_ n]й2Yse#e_<õ])nZ1Y ;6)3P@2ۊZqZ-]߻eͫ`Je\ ~D׌}u>- 6~# &1ࢻv$E_:Ӳ,rHqubxhț!' aZ91V-w癷fV>/^ױo/w}sX_k+llYs%}'؀b9W+qOft_;^@džggΚ'\:#7*B-C.(b6,8c j0cn`bcpx(e 1%'|j}-xڱL"\[KdNGYH6z"vm4fL RI,˦PU#;Ml[g(}J?GҵC5?PUbF+ B2s P4BvT},vRw6 QnC!Q>"e_r?i ǎ1Жsc娍4DQA:x $Z+šf_{jV:6<َu 1R']FkTi#q'֔/~}aB݇e-;+,~T6*Y6c=ԷƞO~N` !k>0 -c1fߜwGE 3GwNIENDB`TreeLine-3.2.1/icons/toolbar/32x32/helpforward.png000066400000000000000000000031571506556630100216220ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs ,tIME 3rIDATxŗ]lWckfi;V! T""J}iX`ɭPU$ @H< JWN BC !%J)Im)_κ;;3nkĕZ͞sϹg9K8ã;@1 !E;RL!'3H|8F@ ۸f_n+":^LdM?*پ)U8\$<:^sjttMavkK+ ֬^═=ȧ! pw+%ǒ˛ǒyCqnNԔ#=ǁ7E`x~1{o_[S&|ӯҕ\-Y3߫L],)M.;)bMZcIR?i(hP |i`?r%Xzc-g^m-|-# mhrd'Wj$_*Ͼ<=Zx藋-ޢ3}+ˆ, uCXmYT `b$*ޏ|YcI0L-i*/X4t编q8n5lѕ ^͚΢iP]@U\gu_.9Wg8smk?H+59e 8x  /d_g[1[ʿ%{33ŗ(`6Gj}ůqz̀wZ <|[}"^R^ρ|2gžO`hI~UE!syf$Jr~ڶ-Zz6+? z|@oah*{]wٖ:TA5e t:h,˒LNfB5P_ҟR0蚲 /8Rk S̅%'4=<0 U۶gB۶,+v3.PٶQUtuHy'EnH`WWݺ> 4 D2bjv;]yH#0wxϗ)V4JG#$HR#ZsIhK#)_ YءkmEZkrS%Ɖ+Nٶ!(\}n\OB̓iխ ܶ \GP)6~uk;5+lbK o|bfB h! \,ܥgF3 j睷|̑3~F^-t-<&m6#u._k Hae[w*2yfKN`QEI#;Z ]4!% ܒ;o/y[34귁#R g!4ߞa/.八|ًRK"ͪ>Bmf6GkC@`oZr#piLɹ5_a ̌SɘφKtw1#ҁHKӲ ˇ8 MpDc)[HHc!:'ux|X)j~ļBIx cȘ!Sń\k YS !=Bh;4:>iy6pҹ2cW]RJTHU)i&Gx>ʋ?R@ItBiQ u;'$qf hD SaÒ°XWL\+W>>*0=y-9\D.7\ -hXLϔqGOI+@ 2JSOGj2Uܦ-$ 3QRs%8}v2@=dw[q-&:m]Ҏ"Ma*2R.uu(0@>ï^{JJ*!Q"2Ʀ >GH)0Mu"RbZ;Wʜ=vvJIm$[鏃fv٦P H*W# #e(tg0XnӔA>XT28zKc(P&٦ܿpەiAДX%vl2Y%drFR C]uFh;xx+$g{U^P2iS)[yӑ, ܙ ?^9Οu~[R@GaŗV.OY n}HZe;8Q²%YGAQ,י(UܱS{܎$亚7]˿ˍ k@YٞL[HWLПhԦ ZLH\%ߣ ԰xM) y%Ow8%0`|G PH|TrIENDB`TreeLine-3.2.1/icons/toolbar/32x32/helphome.png000066400000000000000000000033101506556630100210750ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs ,tIME  3VUIDATxŗo?sf粻wqbƉb'M=-Rڢ h6}X>BJxmQʦ6I|]ۻ33sNvCHR#}3].;!<3{i8JPr_p8d:V&>< < Lv@zz[>@o8w?N˻`x %LًiEYཅ^*ୂz/8{I6Z :ٵ=ı]oHNKɆ .aLrY4Ȼ6Q <#fUyT|s|thRb"N*M6s5ށɩ߶_Msb'}DRK2RBsh:%7#ޮh8WJvҿ@u!D4qo&& z 2҃;f lch> y'EݲDo zaԛLoivgJ6A NZ>tאOª67v@+Mª~ |ⵚתOE]\zI7|^}o|<_m +Mڏ{Ph2z҉rkPW  '40t4[s){>T/9_r@!N;p8 {v\<~2];g\1'08N8lN-R%_ w "-40}̥O lenV״cY>55%tG0/铖!7蠤7~a賶Vk/d0{ٱޚk~(lLB@jZ=<>5/Qbd0ON JїfSSSZ=āt1 yaz:񳄕,|dJVկԜ֭a-îωF0ݮ9/B6z:IENDB`TreeLine-3.2.1/icons/toolbar/32x32/helpnext.png000066400000000000000000000041321506556630100211260ustar00rootroot00000000000000PNG  IHDR szzgAMA a pHYs B(xIDATXåil\wy3{o8^}=Ϲ9~m4Y@'t`lǁwVqp;T$C`u\cXY9^һ>]1~{@:hmAru&Bgc cce&>±q\%ۮ@ۮfe  -7^̎)"Z  !T|xg,ϼ>{ ‘cP(|я'ж 4ӵ[yN.;/A&d<!^`L%ђ#qfKȾ{Ndϐ}v}H-ܹRفkxDVD R1L)/ok? ;sfZ< K;! C_V,Q2pʾe- K۟#Z@r@/pmW/91Ua!ΩamC]LqNC3doB`9J%[ ضwl ګ $aﷻ02%r~c)&ZeI+mq:m$?KG@<FK̖ E\r|]r֎츺Z+\"rKΫD͝F*vΩiR ,2Q805i̓PRe}N3+ τ.xwFhn}7us$obIX[FMR*$bq'+|pc3SŀB@bSŀ-!GP2|" Rj,b5bÙ29א_%Ko.!VfB<Ԫ]KPkB =Qp*WBOO)JT+݆0[,RJ֞VZ Kk6N}& 2$>,?\ՙ\X odug)fNI"Ra8YHD$Z Lj s$O :x>~BrWւcRjuTJA:C+A8zZ LTɄ!{z;vr罏 cΒ}];HR H~-3 1e<W*ijogS2 x,XD>O5+ZiYͧe67.-3ΟɵG~/y}' HD&#*KfI'|'&HD$^>G ~|cοD?oyD-Hūy z..WHJINMꢊH(ntR=VƧ&]~15Eh-$RT'`xo5合VQ߆Zx]'7Sί0jC3I0χftDkam1JcQZ#Ɔ()88\bmT08Z9@6$X>L)4FJ/eMijFsͤҜt!^FCkR~@5&jA&3=pjBmGږ_nP?'I55D9k(HM*QE,"K:134X <g|wb m7% T"s2{;=Jw_@O7 k;X,ƚ&" S5f*!ib  ntǀI`O_-g[HցZ!i^z(r9S<]~u nĞpcG ơ@I$IPo>z‹/ཌ~zwuMqh)(צ(bZIhrՈ?zG `ŌΞ\ s&na3Xrt)rh8ǪMw6Q)LW"B ВF8њxUT+D[ `*nR۱ r1[gD! S(iVw$H} g)ZIhAB=bZx(}庁ҁgN oH%c\Γ_XV)-~#K9\5⪁ mggkRD"N`ogflp3-t,b*<ʾetgt2XHn,R}Ӏbݠ-0Z؞=ͼ~.??x!X:U9/igU{Sy~E)gmMI(>K۴ ŭK;*b,D5n<֞XD~3RvēqusV OҖz{ïeZju5w1[G1U %z yhC -d7ܢ}m1]ȑi&fc' Ocy&TBK=xZ+I."0xot%=knFc`:-t$iѹ:gwFۺ`E!ZwCQ%_'sd QiUM4Ihgk(cKbk- /M1N 2sZ|@7 !IVPG"r _)GRJցTZyp2S .E*_7${߲ )YQ sX.dxt1Z),J))S0SH$Z uꆩRo( S\ԮJ`)b})Gd!`xJ)A\ϿHU)"Z bӧa\b1Ş[7EɏZd <$^PG ZR?KŐ"Dox`FIŽ15J%HP鵟8.4)ZLru lJQvphxEIwZ oN -I)w쾛E2 R1I& |Q~$9 /z8O 2J%D!ڛw/wI+nrcs>z2D(%N5bM&71T"{rǤn"庥'㑊S{&p#80(xi渤;Q frAj'wdѲKJaWRDBn?xp\W x55FQ.O!|NJysf)]?u#Ċ.2t=[ag)OG'C& gAl>k&jϿAY5y^̊eIx3f$t\I2^ȍ)O9u7< L7y[l-hfa(4R''D~2bl P^j '!`"1 [*V@o޽S'l@ hrO}yZ2Z^5E*Y x??=W36^z6+0>`9(qyNҞH xZ?N"LIX67gnV=f8uRRPue`q)J6)YDUHW]E-1T@![+:n5 [z7466"DƐD.HHR=t]g37t;9\F.RC}e ])_BNtB6+J~7kֳۺ4< SNnc3 @?am܍ڼw2PeT_NB$y(E+G:pY+JfL-*ӄӄZvIENDB`TreeLine-3.2.1/icons/toolbar/32x32/nodedelete.png000066400000000000000000000023361506556630100214130ustar00rootroot00000000000000PNG  IHDR szzbKGDRo pHYs  tIME  % kIDATxkW?Kj? :QE.DjZMY4kt*V/H9^E*., 7E4M(c99<zժVW_<)LMс,,`M-/5b Ơ]ya~A>ǭZ`ftGQ>hjO2 QD)1Eָ.=.9k(fw2;&y(0,-(Z@kf=G%knkAX$Q~|w{{e8fD*ψeU֭JZ.Lڇ95Eʶ b_T @pqHg۶r咈FHƶe^)y%Y(ZWJ2-@Ѩ:dض 8WJ2JxZ/c2 핺\; Fkq1eRbI(-w@@,pVXBkǎ`_n+Շ"VBIgQGk(ƲĀ ⟦ܯh`5~+mJ ̂ɤ4=xGӘ@8X 8~ :$o$J$Armmة۷,ʂ@vk-64ٲ`HQ^h-7e@]YDw6TfZ2- W2>|X+ժ7U܌4O mkIENDB`TreeLine-3.2.1/icons/toolbar/32x32/nodeindent.png000066400000000000000000000032061506556630100214270ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs : :dJtIME -,}IDATXåWklUEf-}HyتU)H"DcbTM5P>c?1*QEAL4D`Ċ(y9{OouΙ3̖w骻yM>UPBCf9X9d:F^J.}ls΁R 2b@BOfFĀd'2C zJ[yx=% 3=zkkQfbc$(6B`f}8r=岑rr :^X%;WG"{DQ`bnϰ|& (^6Ӂ.1.= xEU nx7`G`ĈFN1iܹsVRXgg-㕡`7~ Ll޵%1'Bݦ"'|5rL܁Šݻ4,;97keb;lw],\n\БICd+!f @ wǸ$(ș 9hׇݎm&H@U0'!8UA>T ]Є])ƂH.ALX;%Ȝ Fᵃj!dgUQq Jj=Cy4\@>ZHOSa7*Y"avn;ܟǡd DI  M:?ln^Q<*$qQD\Í > I=ɡl>7) j\T50Yqb澴:b zU;$Oӥ{F&b"*\@Uq *c錵`0$G8q0CH$3Yn;(:#ĮXj͜#&E>9ȷ 4ne5}DL|kM))ENY"mbVQ QU-KUǗLƹKJ nhǯ}Zg3ۧꚕmNC༵O8 _>r.h1j5*cc7~4PV Ƃ,])K{i')OH7e3<z335pңuu=,6q@=ڽ̙C7Ol?Y ԅc@q}TRL?L|ݶmG k[2~&Ba F8)h} mmB[sSnW,!Ib S@='Ns$ܚV>'lG5-**V,teS"ObYr@'ߵk d YJvgjz5L7?M=>/IENDB`TreeLine-3.2.1/icons/toolbar/32x32/nodeinsertafter.png000066400000000000000000000017101506556630100224720ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  tIME  .rUIDATXŗKhA)>J6@ԃmJEҋOz( P{A HAEPT5{(Ƭmq3㡻un d07c hB)|[S>ut(&RG@ lV>7m@+f @#PD2 gR 9(/y䮩7TV.iuC._yPffXƕ/UJs_ 2><*n@?6`͚ m[HX,QkYa?>NV9|\]RFFg-~D0Uoii)s>Do<~x$-2oz;::G? ֍T- !qz F Dj?af=!4uxZxG^8trùs|w@)%RJ)Yr诽|9|] . ㉄@$1ҳ)럷j1aJ[@ s'ԀL P6"&Pk ?TH|ت[ݴ~/rpVl upzR'E qĦG0e655xhhhA/();Po-y $e>d8{>x2TRAq!Pi;<ӰfȜ /-@Pc`]koo:rEvuat95'H2rtty&tSwҪt2.7q |'zj3$uG#.u]t~5E`ʪoQюW9`+TT +%??RJ5f VK!02g#mV ׯřԙ[r?(ȾETvA0==ϫWߖr<310L حAyy9i">`IŚWeaffׯC.b& pV|4 ƟI,"NيD-R _~]D@ӖSz7n{D[t@>J'}@1cPSS*ae6v;l,L^' C)JLpi2_+~3zc(É xsξ"io+4{lY؎VڝxZ-6 A(č81=ƥg>;%[ rfR?t]gܼ};nI;erӣ xw872FN348((,Mg{M`;%^??*Ea;&k?lXXoﱼ *g08OP߃!cJ<c U:!sQOT\7SWeO\v.^_ l*+vwLn<Sݢ_ˋk%F̈LZcPDv&1J1* <9={,~*!_JTyc= xԘzfe,f2G؁ _j$[ox8}}~s[ P6}htj4@E-e\l)d’lF) q XB)z`Z': 4W6"1!Vx9.ࡖNt;0èR3X&W̒T@Q\錅BɅ,2 -B)ͻB/i@TE+3\Cmg.FؿnJNǡehr5T*.KNe*92A^y mF6ع_N\apmѼzYb@U4 `GCᷘgW_@-5[G]8|#>yF)f+"t>u24>H:p{k]%:Ϙ)OwIؤ'39fMx+ ۵uDߩ=>7m]o/N!>pIENDB`TreeLine-3.2.1/icons/toolbar/32x32/noderename.png000066400000000000000000000031331506556630100214140ustar00rootroot00000000000000PNG  IHDR szz pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb;pΗF~! 0 Ad]x??00\ w⮪ @xKDRp]tmG@_@?0x 7oĚ @L$Zƅ @K6`20|˝pc`e(Q Hr(\Y!+?@Y #% &* (n @,X @?c|;si{6 y3021m&@?0',W_~2?w@䀿ԁ ?QKۖp1 @D; 7h`(1|N '+3 Gh~2M^5Lfo e}'/v@00d- "02a:'330{PyFB! r!0 JwV0pkOz3ܿvA4/h'lA@q( :/O8XMr@ tWn(>###!lw((8T^fi9Nb? /gWP4  _ ?jH #@tbnFvP_Pd`xCA_%䟟_&_aɗO @CZ} < `ŋ } ~f;?m Xp=[ ׀ 1<p AXCb^e JF9~1e8bwЮ@dj^KGO_D ObMd`': P(fR(?@`D{{371(>ʹr!?6+(q' i D |s-( s;; ''(MR8c X|/r@ Ïj!| h)++$tFlFbဿH ,LK!gZ̕,XJ1K!pŰm< 6!,ـqDv@`~c0@(0cӀ9 `eLC; FX>(`trIENDB`TreeLine-3.2.1/icons/toolbar/32x32/nodeunindent.png000066400000000000000000000030761506556630100217770ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs : :dJtIME - mIDATXí]]k3_8ihҪAXSB+HQi)`P@(OmAPHEЈCklpFJ0Nb':jM&3ܳ{vZsgY^GTu{/# A$֒-*9>ID!%t7)?"4.|&͉ *!W=p.ٲ=Ny>Y{G* Gb#mMNh+_u? oQ6 @5Z`9pk^C2T"9y X`xjG H7yZNd5y\wxrE׋޻db2*av}oǏ=9O>)>9;]*O[vydBQ!H:f50U> G6o|2U$q^7 x]5J]U>|̫\D>T@Tύqۺii۵=7mȢ?MGIs!g+MK Xr 44x2gRm'X i&p~%lЃ1&sNC"BDoױUTPxW>]*1q,ʟྍ?W0b#_Nk(-IE?}D.Dr~z`s\5t3CSkxunxᖏOq ?q`^C7cOj8^rJ\_10S.֓րd]Y4L !C ;N pbanpӁq tSL,4G&SI߼#i#  _xHCl*/=MWh Qe*<)}uR` n i!؃]>BC+B*T"@j~k[!Sf" Q;l+:W\P;G!\\Y0@$'(c>AlzTS_u?aiȰ^7}@YieneeMk坥@^HCY%S=3@ّ ?U^.~̿&Tf+LȵY=Gn,o_/-4iL[9RCt4=Ӷ5j:Μ]pLKOTZL5|%jjQ)em}_ﭣ?1<З8Wu@&д[&q[KM__#& 5Z`:f#?_zJQ_%$Bb=87U,$9 [75קaA ésk*B9,yݺ ܿ7IENDB`TreeLine-3.2.1/icons/toolbar/32x32/printpreviewdouble.png000066400000000000000000000015011506556630100232250ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME  8IDATXWˎA=U] tΙ24&:֚[@p'|8k8%M4q1 3tCutha27!v:9uˆ '"p/hz gh4[Y=D=f+ށ~|rW<+D۷nBhw< FDO_?prN>Z-@Xe1:޼lٜz&AD1\;ܯ9N=6L0ǟNIz!f if`MW6P{c @3GE{7vq`JrqGf_n+":^LdM?*پ)U8\$<:^sjttMavkK+ ֬^═=ȧ! pw+%ǒ˛ǒyCqnNԔ#=ǁ7E`x~1{o_[S&|ӯҕ\-Y3߫L],)M.;)bMZcIR?i(hP |i`?r%Xzc-g^m-|-# mhrd'Wj$_*Ͼ<=Zx藋-ޢ3}+ˆ, uCXmYT `b$*ޏ|YcI0L-i*/X4t编q8n5lѕ ^͚΢iP]@U\gu_.9Wg8smk?H+59e 8x  /d_g[1[ʿ%{33ŗ(`6Gj}ůqz̀wZ <|[}"^R^ρ|2gžO`hI~UE!syf$Jr~ڶ-Zz6+? z|@oah*{]wٖ:TA5e t:h,˒LNfB5P_ҟR0蚲 /8Rk S̅%'4=<0 U۶gB۶,+v3.PٶQUtuHy@فFj,e8O[Io%|?'EDۚR}[L'5鴿ur= yx`MFh;<[gLn.,_XWH]ɍ;vle}nvl}QZ0rh>5P!gYdT3o0ϜTU̕9u$;\Z>5s$ >v]sCӗ ~u$?]oMr(C,)<}4 ل6sZƵNG{/P(`gJfҶ[f,rP 4-^8TX:GK6a{ˀm}]abe?Z lٕWWJ咋BfF'k'Z  2H*Yb{Ӎ?/u%^XqpEjn1bfA`jM(>VOrkWWs#-h@D=@ܥ|O=ݢ<^&] "؍$ȧ"F2Ru܍9Q=FsJxnk( v CzJCz18kQuz.ς@yY@aAө>ޚCg]7hM/]ˢw%em8^.]t a 7yčv|'={-X<AVOH_(pOG_9T_(mlRT[d2f_+oO $Čvq׬D旦ow_]o\{S&Pl>] @v>G荺mF]bGv>W7t/z ɨϫ Ǘ5vE:Ϳ9*5>)Pu>>.Ĥ#DϢcQSɭ IueMx Uj_Cw 6]PD T>{M]G WK>۴X-߇m (tښk{1""{I /KP2a wjV9 az2`p6jN JWIENDB`TreeLine-3.2.1/icons/toolbar/32x32/printpreviewsingle.png000066400000000000000000000015471506556630100232460ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME  (:IDATXŗ?sFw&cwIQd8v&t|@|qҋJ Xm)&pwx _6w.zߟ?ur3Čk)2fLR16޼yg/m]WPFF >|{p D^Q;A\"kD(h{|uoG<8{<~٫b0jw#'׾C4Jv0'IѸ{{UF#2VU7ML:D(F%e*;"*!chTR)*$͋Y($e]j"*{szf-~e(bmL^& _(P*N2h6[PFBF4v} UƤҢ2+Y[r3ɐl\ɄuPӄĄ2FM;Mf%ٙY<^Ʈ^Jޣfaw. ?o#m%"IENDB`TreeLine-3.2.1/icons/toolbar/32x32/printpreviewzoomall.png000066400000000000000000000035651506556630100234440ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD ^ pHYs  tIME  ("NIDATXŗklޙٷm^;vH,U(XW R!Tm*EZJFDZySZ(ؐ.ڬػ>gtcWι{. !lZ/lP ` xNo9҆LǏ?t斖-UUՕǝH$>{w;Q_ݍ*"bvݻSN޾]"| Vb?S|#GN9s!|(2czIs_ڣw^YM8/^l[@~O;wD P<7(v7;+}.]d|i5≞(Epk8]]]߯ʔr)+6{\B:{;<MDl`:;;Ҷi^baGp{`Xn@1Yxvvvd]|ַ5vW\$ߚiTU␫!`(s){W f*e5_ik39 sbRW&q8{{/t߂B>=8? kԘvZ@/r3ZJ"8ud9v M}S9,$RHe 9ٿCs\( 朻1Ub8#'8,K*c sihT,Sv;K$ݭ #f84C B ʥ5RKeY+b*Fht:qnigR,ŲR* Mסظ5L"2%"DEK k̆h&[mm-%1O! 1 &Ţ_'_Tj pFtɉuσI=k@ fs)ФeymZ?Qw+MInQY l}xrlK6Jє>9X>o0^݈pc씹-3T8{IK/W]r%yi`y#99Wx=]Six7KsvҟCoooRUU^ 8k!DHzkmw\@kk+N'$IiH&9W&SSS\.[/WHKւXaOD`{ \.W(e$95MKEUUgG"|>kGm:MڼNG!OMς'zw,LPb<d;ll|gI#F`x#*h-].Hݬk^VJgN[!{.BjQjRjDIQL0fnd>v~Q"p?tiXADk&ND)$ yfZ.G'ȄХu@16sDn- ]~u =`_j'@a "SNs!ZD!Y"]zm twݝ3bb`L / i|xAȀ_d3b6< @7ިo7pG' T˚^Ǟ5²p/|Z~qww,By0af2,s=lL% g@rdxBDIENDB`TreeLine-3.2.1/icons/toolbar/32x32/printpreviewzoomin.png000066400000000000000000000032401506556630100232700ustar00rootroot00000000000000PNG  IHDR szzgIDATXW PUVXn(f bK hZ*Ɩ( "" 3 80Ըt>3=,|s8|s]DD;%Ipdx2>dlSW0-Y$1!!,[[[vtt!?xOaTrAǏ` a<.@ >-RRR=UW/-6Ða< ),,lkhh!9?&n-J;8e_.@fxV555QLܾNU[)1C6;@Cƒk9g:BB~G4.@PUUZA^iSEج[ѩwO.|wd$t|!yO.͘^Q__O{⯎\HΝ-]E}'|n$t|!yy5-@Xu#Πs3;bBk7L͝e?$t|!yy5-?cKiirZ-%{RT];Ak hI:><ȇ0~iuee% :r:5:\)TIu21Q;8#! dlݫ#Ϙo2,ڿ }.y\ ɗItC< 룢nbv#SZEli}|8%t|!y/UV_&zxO6G!tc5KIa<xwA)H U:pI*%ɣJi/2` vqG)=˫u;v`$)O'? R 9Hl@O/7!8[x/6|`RHȃ0aBup߄ gSS oo빹t%jhikͩl- (h%:.www񹣫e6L0,}b/3\ 7p7X>4tƍn vZ :m7Q咿+YQ#а̬}'''5$tgjG3@E:O察W_Tb9 sĽe7c?#Ml aeJ.TQΓ2cֳބؘC xh# |Cp1)N|E(iUEXb2Z"BWnWzb9XnV@3Y4%흥."gΓrL˿ѫ収c"̇6a0(2!JC.*] Zy1aΰ_ Yf9*JuUQ2 K9[!kR@1kc1%c*cc:c89=R_qb}N*J[CG-iZRΰ 'q"z$6]QJVGVzke9JwWp>"Nn"j%NPE6 Q;a"&z\'2d!6 C#! "&1 AnIENDB`TreeLine-3.2.1/icons/toolbar/32x32/printpreviewzoomout.png000066400000000000000000000031761506556630100235010ustar00rootroot00000000000000PNG  IHDR szzEIDATXWyPU=x[ˤ !!HR@&% ((5(bF﹠ʢ j! 0!:`-Ȩt\fsswE""ヒ`Lf1|~$˗HKK;ϿΎhaÏ8xgİsuuJOOikkaЙ3g(**BCC6>D<==W[[[)33V^[rN>6>?Xo''{yYPOB䟡$Km|!0b%[677Sniuf'RąX)%JCnaqGQ  FoqnII e9dikα]1+E]wdhaÏ8x#zBc¸ꆆJ>6!xt-lE2yGC]Ckrssoі Lﴴê履EUl|!uPu 0AiiiOUU=3kÒUY.E.:B>)r ~e|A=5T0F\yy&8p~+ht`+kI-lyGQPP>>#&28XXXx oTVVRSKwͅ{-/g~ܲ ?◛[nknn~0^4&-0a,:w#??۩jSW6^///$zQAEIn*J_y*X4}m3|$ĠW32#A 3/( QcU2_Mj*XyˁKjC%0scѹɀ"^=/3f0l3`(EqRIEjb'WhԯjW8AC8  Y;1E H47OgLcX/06CsaOS=^#1k\nq. IENDB`TreeLine-3.2.1/icons/toolbar/32x32/printpreviewzoomwidth.png000066400000000000000000000036071506556630100240100ustar00rootroot00000000000000PNG  IHDR szzsRGBbKGD pHYs  tIME   -?IDATXŗkl;3>lv- hx.AVZU*QWUR 4["!‰iC5kٵޙEkKW;sι9#?Be@!@W~EKbLkÇܹ_QQQfMavbǃ۷n ={S>@߳| @/սrȑݵ/J?+LLLGuU>o?vtJ)tl-Bh ^[[Դ{?J廧E_m 9MHR$ 0mmmp8ߟܱcG̵Tk7R}ļ, ݞWt:viT*щHS`*//CVzA:n0>՛|-u|)y B1Dn^` 80dn33=r(ez5tí {/50\6;;1S)gtu"0!}J';SAJ)Mʔ"$ajfS"#͙]cҦ)z|{E;X[) `!ޖ 0=b,&HFɀH:T=$\|+BW_DgJl٠ykܸ:*[e+@(sJCq#EATM33cb!@wB^.S BAxвiʹܞ.82 tuW%AV`\?::ItcO5b\k3@i2BX[dF:ɩi=z7.[$`2 A0a]@2 ֌[҄H@: %0@.Ёٌ!0IENDB`TreeLine-3.2.1/icons/toolbar/32x32/toolscolors.png000066400000000000000000000024641506556630100216670ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  IDATX[lTUtfLEZ,XJ-i@M\c )hb1"Q_ `J$H$\#hCE r,g>v:g)霵^?묽E^=^.2*UVcȋ{MA7b"i&жM7ɫ2,_=uJgeTCY_H5+b)1ltwZ+^/5 ewFSg e)@lTZPJ! ;=g.\v\_4ĤӠMZ#^OԴ[|r'b3]s(}z0DUY ].aU Ii -*Ic1.PZDP; vFvw cƇqRnB% svzCc0N]Q.7z]ye b/ t4_fbQn8G񾜴t-MtҾnݖ`v|0`fOuXlP_iәujn:3Ԅ1<z|S85ca9Yۨ ;/6O-Iq^%"sAPц3`+_Fzs-bS\9)CP@p $kMT,Yv&rF5jVZXX'lʲ=^,}foXMHjLYvy& %@ &߈ve2rT ófZS㍉a467+[3\?ۺBGԼ:OESh)6C?ՔҘu`ǎ__ү2J IENDB`TreeLine-3.2.1/icons/toolbar/32x32/toolsfiltercondition.png000066400000000000000000000036721506556630100235640ustar00rootroot00000000000000PNG  IHDR szzIDATx^{]U9;3-3w|̃@-Ѐ`E(S*(Q BFE$ B[!tLtνs^svnf$%JVu%k}BoyS*Zx U)' RFEteٶo;(@o4_jri(T9YBUBuAQc0WQA<BJpfL EL%@_*u% _9;F68SIe2dee-g<-(&J&&eIMUV-K xw@C&ST穞s2'2Y_x(/PKA}aKHȡ'˔GQ!Nh/|(Yp.|@&Q8 E\#.fi&URMINT5'[gˤjl-qrșwI(T1 <_K$%`N;&izۉ`fcL?)x"QȆ991 A娸0V*(JX%d "4l;L_%myf>PJ_[JF#%J<Qc3[".Mf1lOwIf5P^sm+uM,! xP7ǣr0Ô2bĚ "'1QNYޱf9v#3c_ @ ҵZxm#ek{Ps]I҉Z%n} qIL_tA ~tz 1V,>/RwU+ՙeM<OQ9iͿ< KGrMM ..1@'Rlq5H/C'^}K3gTs.D9_ߴԆ@16"s`XCh?>Dѷ[m 03 M 1'"7w4P '<ڷݶ>903޳}-7h)BJh ITnF<99ʉO̖7rܨՌsΟwrQ`U E:;nv7]yV5% z3#߿C@ǿ]m{aruA8pk~3rgQ[kXZ}3{c,?7=,k~CGS wS]Qmjw@'ٵ; ]/-xywODVO_')Di۳kvfH@EJQR(*t%Q D8zbgdɂj$`-%<`4,rz#7*7O6;{!1{P(N.|q63-Ǯ"䳰e=/ Xzv lh:ڱe  XVei˹ .: 0ʣ⎗Nu!x J[_ Q\ϭ; 0+Lynӓ[/juK>}1c=W>p9\ x')@Io9wYcz}Om-6eS}#\A$ :<;K'k V|upgvW8 FW;^R`.`2D4npt'g|O \0lӮiƿZ?LIENDB`TreeLine-3.2.1/icons/toolbar/32x32/toolsfiltertext.png000066400000000000000000000035271506556630100225610ustar00rootroot00000000000000PNG  IHDR szz pHYs  gAMA|Q cHRMz%u0`:o_FIDATxb? 899٘x5f/@1rSZZZyu:y9 sGgϞ}|ĉ{hѢ} j 9 sh0Pp6@1TT`p̀Fb~0A7ZZdZ1VJ)!'HΙs8>c̫O_2` $ 9P8$H$ן֞{~,Խ-9kwJΙb#{scZ#QJB9'Z<PA6LH@3 ,+:])Bz෢7ƠFΙ1FB86Zz 5J)1[|I)0WJ26a`&3H>ft J K'|ֵ轣ME9gI)aCca!SWk cS)\_W@Yٳŋ-,,?///R 9 #恢nPf/@{ԩ_|_UU_QQ?Q`A쿛ONNA 9h׮]`Gxyym tuu6oY #X0(hAHP<'--_HH2gϞ/^;נdv#H '$$z t\4Pf/@$Baaa'޽(KA.''?)) \^|?@9鷂BP4r" rYׯ_a7n|"##GGG˅jc>X/_ 8JWEφ$Ƨ?rċ/hb?T2_ѣGAv#Xl@,;w}OPA31({\g2$..(8;Pc+oe,;Κ/_ʦ̠e۶m7l.̙ԩϝ;*xqD6&FP))(NA ̠J `Mڴi \kgjCb =7͛ @XnV`| /3shΝ-ņ a FPtRNQD93&m4fR砖׻5F/|rj"GQtJ b3XE({aTkĸ$vVNSb*#bmLH(+Ԟծ3z+6b {[w+bAɓFd ンwF=Tt P{c&J%pFd5A$5%XF\x) !@_{J _e'o>Md۞oW%1ʙ@BO9_Njyan  3t-jBVeeG)V j<ѿ@m}vVJmhIENDB`TreeLine-3.2.1/icons/toolbar/32x32/toolsfindreplace.png000066400000000000000000000037151506556630100226420ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  oIDATXYlTw,`<ކh,P .Cb'}H]ڼDm$pQKPDVj*ME&UH0b}gg[xlo==|sw]B4MúFQE00 #瓷MDUvNsi7p)'N:::=T AET*8`Ie|>(ܯik4MJ<o|\9͒NpԄa3%|Rl~?^7$IE}(իIKyȲ&w XJo=hp P@.6MߟCxldTd_?F3 k|d2HDP8u=4H ȒHCmUsmuF۳111hfI:a&&P+I|X,l6[Q %h B! TylhAVIg5ҪNFY?"fa`*dzzFin(U1 u@V3'UhdUT*E$!v7܆N'̇:Q5r`<|$RX"CF08_P \3+5[`>o28f1bjq@(A4!2( $vV3<|誨`jj@ @KK {l2- 4Ը1b NfrgӅ g% P0 O>]cXޫ5O<pN|l6s555>|Ud'#sR4v_u뗣 NvxIPÑs&a$>&OgV$~JgΜ\QQQmmx<^/@u Ԕ'WnIi?2s]۷\7`A׏`SpqVɚinn;N0t:QD"$IbX~QIEY$;gTVֲA&>LJQƽ5Sԝw&cSUh4liiqDQ4MC*,˫4T]|gq:'ND;!*s䟱8ן]]] [/_y޽.+mZq\l6N'n\.Nݎf#q M"6.X#:bA:_Dɭرc3Ǐt8bdd2 IDATxڥ{lǿ3;{?#DqE䠈H|U ibdG DHH TP<"9&JI)Gh(U]G䀠GM@LZ`g>cvfw87LF;;|~6jkRG̐2 JJVK>7HJU[7<j|6RX_Bea沠PĨ9QkڙGlz≚-N~҉ޞ틒 --ǶxT<& :(AJ)% EvBfR+W.I~JX?oݶ%K8̛(: ]i  T5 r9XT2jղvh9ad~zh%f2y|&C +c(/AT; f|+k_?t" !\Q8}pGbwrFpDC0G0GY0v, h)%Z9n$0 Gz9 靆!TT͞0vf~Dd 8eLfG)5wϔdsn$1L!Pe#J(N,G@4z~0]u1̀xiRԩy[C0R,#s`gy3A)FV|MӊVJ)a f 0]i04 !Mz OF}7 .lF&"@M5Q4Mw]#PJAz.G$1FIXBbp*ʊ Ə%r 堏F )%{9+uq?Y5XV t=N)t]ǟRpҗ;?/  3YRW #?˒G|sC@{J+1(M-6G_;Y҄Iu L~hK\)\))w=rTWW5@K#144 ˇBIUX*p#[ض[Cĩ*U#rv<>qx7ID,!c3\/k~n׵>cT8Ƣmy~2-Ր!VּpZ"}Љsp}`OJiȨX%Ėv؁ǏW~"@8..n˗/۷ᅧ:D@<t`QL#cd1tyBYYY xyyJ@ _߿8-Fׇ {@4(^8@rĂg PP Kŀ̀!Ă0  `q0Onnn===Q-@ dǏ^~wg28qOf8uX̙3@!\D0>|#ZZZ`>ógDEE?yp-IIINNNpK &\q̷`{.@WWW~~~ښʊAVF1БJJJ`}@S@5rhX244dfx)0*1?I1a??(ӿ_`9 LL bA@ ?0< ?1 14`b+? -G g(pc`eg%@1K 1vfC@ó ܪ bJ o>B41ps4 Kb8E2T?/0#a 9 r W/|p ? e * w0ׯDع>y`(,=082 `؂[ ~f7`d~=, /eb ).30Abȷ  ?ř@ X˗/ ? oLup" ^`Е,>&?`c!@x(Osqq o߾1|A\JATL0'  & ?2O`I7#9g6e_޼y}F@ %U_-0a Ö-[n .z988j@e+Tr3|Z//×! @,riPA0ë |0" !!@,"$`50~#pAEN"(0@,c~"pk/y~g,޼9fid6@k !; wfX> X~Ú`-'( E1peo10|{`e/# YsƫCzl8 Qu'Ik3.8?,+P/q5ð9 X` 5, *%6\lBFBm@GÖ` iquiFdGv :Xki@Cg;Ć&&&0 ͰɁ," 9b)*RRR@1&x^"$*?~0&"= JU=rϟc J ЀIENDB`TreeLine-3.2.1/icons/toolbar/32x32/toolsgenoptions.png000066400000000000000000000035601506556630100225510ustar00rootroot00000000000000PNG  IHDR szz pHYs  "IDATXkP]n.Sh$jb6a `v&-MZ;~`ژ̴&Ա%Vmf8r aa4IDp_.>v~89s{wRMݝ'E+%FMeej軂iߛN̢4JE-@bjV! ׺{F(}16B1ۢ!I;Ie||l<$vIOF% OCbjeEwV P@/crlwT/ P;졎1[t ʬWaǮsjYx\YqCҫU ͊B M4iqnxu쇎$ c!lğ"l6"d])*t:yHdD[KZ7 \هk>l iIKJ"{e.@iELMMI,觕J`˄H26~ ĹWq;)!Ho2X҂t;^q%6yְY-a)o 8aZ $<tvzzDV(nDD(2COM}hfzPMfK O3x.::K1BlPۓu 3 Ѩ] 0Lk>9)jYUW._sY%Η 3_i1Tp?QL.d`}of&^{ ib?aRt@ =&S5>9(of0=r-xsQ[]S= 8ƒ()9;*.I3+YN'P 7__>:2s&T| 0(ܼ p\VQ{- wW W=&RKLBܩ2"cnw7Q Iai<̣7PQZVJ`><^s?9ɉ o1f6ZAFgU^ԃ~8hqeq>7cf3\x">O[f`G)}eԏ`{Y# ۛYR@coIV?6ߟ?#AGCM^Bfs_iaA ̝(K%y%#q|pzD ߈s^@᳹yg|a'e7|@ Ho dggKĐdGƕKAl`M4_cs_ƭ:(\U `#!+vw'v59B"/M4Vyoef4/€p$K>S|مF|{VF[sa&9Ɵjtnq7E$ z&I9r~J}2'3 <|`0cb utQ\adqXc4:( > EUr>\UtA{]o0RV IdIENDB`TreeLine-3.2.1/icons/toolbar/32x32/toolsshortcuts.png000066400000000000000000000034341506556630100224220ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs  IDATXmlu?s"Vg[j%2jf %df\^%qȘ?mO̽8fq&" 8ǚVphs9=-Ÿ+}rsʲm[wSl$c Ao޼u[1~I:YS=*ȷ xW,ioiD'"@00fŢ?p=>UkϲfmWKeR2 \=Q,JI#M]W4RQBUPUT B O}J==~zwX7]O _GX…QDz_{uEB03 qB0D@ʊ #3RQ CgPєf5:0_b*`̌\]8K\ii;>.!"x <6S\1Uj3`  #1s | :T% Tq)F%Y?E8@fjN ꔎ:/Ih& mmm;vňdz0U Ff dlt ItDUhTQDY(7uR>$1+LԒB7>̥q.^H>'HuV>n#IIطo{e=Ԍֵ\3hm,ZLsK3bs е]%)c4CCC47]K"T`X98E >[o¹דH3dYFǪsynh$k99TPYI6-Xّsa4\*B}Aϝ?KaֳL-xK$Oo嗀R-f~Fa(SU>GІ5ke4dj\E7T7X*JC~;c},x0 o: Rӄb8=LE(NClP5ڼ_(ze D-u)7{_t;-^cY8?pZ]Zݛ>yz :o|?}#&dĴ0uo@ÂlN9IG 3)MuSkCCglj-rm+3䫢i&$]Ra IU*cy8dH4\!BbR:w (e^zr`SmR1^,bXp䪎CWMg aQ̯YHKnz`Av|K?I߂>[ZD_?[#M|5^zx^ hIyxgOPAUd gk%SLx J :DT*W;WK-˾LV6.fe]vM/"fx0::SGjq*3Wz>4E˻^[~?3+WBsK3PXjUyxIc8٤8&̓ճ- Tm?ƕy'TA(foh㘣&7o0eޟEB|y^`F>g`Ο?79dQS3٫P2}{x4vhZ#wTR϶OZwgkfO0YDf>UlcK{`l]_(1 +u IENDB`TreeLine-3.2.1/icons/toolbar/32x32/toolsspellcheck.png000066400000000000000000000033271506556630100225020ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  d_tIME  ;gdIDATxŗOlw?g׻qv6㸶IHB-ZTM( . C\9pAzBU$%-&4%#)$$nj;z^pg8iK$~h77}}{P6S@(++k9I6&H|lpd8~ nZ;L5]Y@+ׁ?w_қ)6? <+2= |$ω <.ߺbTX77=úer8|8~ߒ{/pxh<&5PSv$$[| @v:RIOCBg1LmI@HԚMQgi`((U`v;֯ȈsⶤojCŪ. |ցfwI!y UY7L$@ԕ 'No$MnJ p^6 EOI9x8 Ylyr52~ARYJ QXȦ;yIŰx8pEyB8:$K/VCNQmaJl[Eyn_n}RA9h mJ:aGdZܠ2+L!$#x۷{^m4Ws|m.m|.% uEv+rL(J6Ltt )aw\Σ2&ٮ{5~ؾsa.qf:=Ʌ2GT~kзYApK-rTOkx<š^USt2VQ"Q^,pL.I $oOj66 kmm|ѹ^XP#>R jk nӵFe`:%Nuxp2hNr{q67Q@tsH-W"fȿ0Q-uJU!vb(R]T^3 pc>h1kB۩5q3M9Nr=m6Z8!Z=^#_.sst2C)-|lKTYE:CTħYd%2)p%N\/IQE@=áhk/Q/l{{/0ϟ&$Bݻ/ILHz;xV$#*0F|[o-cPJxС:˗/^zݤFF_ 7bc_{d5_q!4=,JH(e_)V⡥ѣ3]?ieeeDEEN>j &Ďk !zxdž@LF9IBEplsKAie_^xϰǥ׃>x\` a{ 6OO?'Og2j۷o @pwg-Z3a 31P&&4 xGy@kll~(WL&AZ(H;wTZz lܸQobrz1)񠬴TQ9Xy SCزMF(pDy篿qXK|#;bzk \2PlD~}vEMM{FIȈkomʼn xV@Z,⭹ىc? )i| 6[31 @M/@jyx|4x57'햩  0FX'$Ō *!BKG_HNNn[ti_ }IENDB`TreeLine-3.2.1/icons/toolbar/32x32/treelogo.png000066400000000000000000000030501506556630100211150ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs:tEXtSoftwarewww.inkscape.org<IDATXklU3ݲݶnKˣح -c|R1!Q P!LbD >01/Pk0Q1ՂFڅ>ѝ\?,fwfM<=ϜsgF"Ο65`>P 4^b=RT_@,3߆oqU¹ZLrSk<7>xm|%?X"n6ʟ`䧆U!S" t!F{x\9}%(.{%kƝ?(6SCiü~ÿP0;6Snfq2=ϯ{9ND pu*-5Q$_@<H%{:l@Q#_úE̛n:_Wrv(3xRNN|50rwO4s1ҕ6֜|6-J^;@<4L$Z 2˒,BZy2#9Ry;oYH9b `fQ#ۉ;={XZ6#y *^JaO1Ql/C.+؂}9>;+7e_ٮJ@Yw N jmQ @& S&d3 q!n PXe,R+ J ?&±Ϸis xۍ8J\tsoiu5UUҘKWxJi&"7}VG!7M'24@dd Q1'X)CJ_u2}uqzL^a1Wʘd7ђ2 PbQJ˯կZ&S7yUD p WUUIczb=w:IENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewbreadcrumb.png000066400000000000000000000024441506556630100223040ustar00rootroot00000000000000PNG  IHDR szzIDATx^[l9gnmi c 6QMLHH Fjb^Qh}Hj!o1F hZ 9縝P!J wf<TÃPZױmm]gp͎Nkk-$_Qo{G'eyÉhi]=RݣڱrEdXgVjS#'Ve Ҝ8s%xz",^Vư @ۼ.Fiy $!$}a1Jj:dC/dbք?T@ҹGQ]HB֭,(MK<9,hn MUM/(%h4Ƒؐ& 3{_,ckStE9ZXywBxt"@@x$BIXᐛql6p-lXB:xG,CE"CcA)M<7y2Ҕ;.\EJ._lX ߇c7mRu18n !?Ohy$Rt(_]Sn1#ąDPĥk hecpԏY!0EEN8K`UB u_1δԛTRlSCpD".T%:{oo/&Rr;4aؔ f!PwVĴLQ x1h EKyz.y+SIH/ IPȡ)_ q`gKDIo>xt$5|I@|d(h/4D) 8n*2WQ~;HcQ>ȟK̜"04S!UtqB{L3v|dsPڼ#SHuj p.EЙɛXT%9{{9ggڣŅ=fCA@=u?3 X1|yǴ8- m,7۝3#cV*6r]?aG4^)8pu>R>*9,+-e/``^~7?o%Xr{7yIdIk0,H^2UC]{)!ݦT(8\b36!HÀwD n!m@@|}]yw }J8R $>voW5O/jU:<eـvIENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewcollapsebranch.png000066400000000000000000000020551506556630100231540ustar00rootroot00000000000000PNG  IHDR  hbKGD pHYs KY tIME$,$lNIDATxOhU?3M)I5h#SPCzKD$<  ^ ICJڸi(ZZ!&mɿμy[n6/9|~{>j޺Rw"y}53O{  #ѩԑsv8s@ѩ/WVl5Ǧg&p]}lzF$-_4]c& Q(;q MĶ.$$CI=IY0l*('rJz<"4殝ANJHFy^,5ȅcjyh e"QL3cƙwgqH'kI7Jj.l4EC!kD?wjߖ#'sdE;NjEMj1B(|_kTI\v~Pde|Tsc R)!({ r%XS%7 w))dS/:\;J58BYAC@|Fyz |RiM(52Ѵ=Y̴Rͽ@R(䳚dcȔE|/)E@I.A|y\T4J;畆ʪJ;g{GtZIlc5<kK6XVvc fHlH)r56je~<膠69a=QLfw :0N \;÷%eON'M=}~o[̅vRӫ)/bR@;<t9re{)=J:6ƻQ*G_:GH*nEBJ0;QQc#/.JǼ#IENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewdataeditor.png000066400000000000000000000030001506556630100223030ustar00rootroot00000000000000PNG  IHDR szzIDATxŗ_lS??b@QZ@66U"CNڤM4UӤ=mIZa^6UL*)%)i ı1Nmc;\7+#{~=^?7K;^O/A-_>}3?;|A=J\sN2B1MaPJy8'9ꞧrc85y@}%P)VB&^V7ԕ5~7l]76x301ZVLhdcaps 8@\7_MޜO\br~+ ks#<[udžib6'x~4!l/ =SӐl~]]""躎aR)p_#$0Gw?w)PJ!RqƧy$:Q[vF}>26mWl"©u `} Mm55g<$D`.8im23 i%f~@ӃV'mpvxĻ|g>BmcეJ%FM Q>_F$i"pju]Z!i6:#|zkbǎ H]&Bm׾ڳ(]fps^:@75U|.*L&C z[]|F_&t\o$PˀR>as.uwό6e`&4MZJ*m3; /$!0}$JdUmA@I޿ww3[hʋ۽PbHZK^3J{ (S}zi]ݜ|ÆsAKvqp]%4 !؅)oi΀o%Rf ar۱,J jkJ@_)d@Vd,dBnz{{3u E[s4ť \>O&0 l&;?Y#`ebj}]ױm{O68>y'o"pQNEPܹs<*"9zzj7lp35  4i-|G B5!Gggg=HЪ: jJ.㑾K`Aә-aF=VB:d on"3(H?cLOpb'f>`lpv3Ǵ:Q7pɽDѦy~F$?wyM#=!X ]o}ɶLQJ#`)Hسw;R/'>XRIՙW.Nm;躎)J"b@[h"R:KJ3a)J)Du XV%]XV_S, _EV V\ 1j JAIENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewdataoutput.png000066400000000000000000000022531506556630100223660ustar00rootroot00000000000000PNG  IHDR szzrIDATx^VMh\U8J DZJH$mō(*kڦĕ HQOI$13M&OfWMi2U n*хJM8ǽ~s9}߽ȱR]nnƴ՟۫!z- JJ]1Npv+O< kjDcJB 5Û=QJ^9Q8"{NZ)ĵӧ~ƍ!`:B"13g!5ʕ/peT*UJeryܣ5#/`yi gnqvk85ndWVtvvAD_ W$J2Fɣ~Zܩ()"Db _(VP_Z/\^D>_l&sYZ9cl,KVo 19{ eTVPA._\&LJk/̡XZ`)g.+xj4@qO7wصk$aAe6}!|"p`?(90p)6P dtoA`o*tG',c2gsy:XYL]DXjXC[Br2 [{CXS,)c -X,pDwpR 5I5o~k|>=?G0t|:/XF&S>9=MdB̥[5l ?X </{ɵ4G;#Ǫ KA( )$7Xڨ,'>[1Ax?bj׮=;fN:m 7w"_(l`ҙIfgɐKLL 336\p>4Ip` bJbs# ݻUrmχoZ\߾0b aaAasNpS4T'lN_?q9T=4IENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewexpandbranch.png000066400000000000000000000017641506556630100226370ustar00rootroot00000000000000PNG  IHDR bKGD pHYs KY tIME$FLIDATxMhU4&iATBEsǡ/9%^z#zi(JE~M{*/XcD/ e.b"b۟7nP TľEGH卟 {(8m ݭ b.~'=ħ%qgggk?zr$AڞGǑ8A@M_i88nȵdGc嫛}ny ^/Oid !X.CI\vVpoDwIENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewnextselect.png000066400000000000000000000031571506556630100223560ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs ,tIME 3rIDATxŗ]lWckfi;V! T""J}iX`ɭPU$ @H< JWN BC !%J)Im)_κ;;3nkĕZ͞sϹg9K8ã;@1 !E;RL!'3H|8F@ ۸f_n+":^LdM?*پ)U8\$<:^sjttMavkK+ ֬^═=ȧ! pw+%ǒ˛ǒyCqnNԔ#=ǁ7E`x~1{o_[S&|ӯҕ\-Y3߫L],)M.;)bMZcIR?i(hP |i`?r%Xzc-g^m-|-# mhrd'Wj$_*Ͼ<=Zx藋-ޢ3}+ˆ, uCXmYT `b$*ޏ|YcI0L-i*/X4t编q8n5lѕ ^͚΢iP]@U\gu_.9Wg8smk?H+59e 8x  /d_g[1[ʿ%{33ŗ(`6Gj}ůqz̀wZ <|[}"^R^ρ|2gžO`hI~UE!syf$Jr~ڶ-Zz6+? z|@oah*{]wٖ:TA5e t:h,˒LNfB5P_ҟR0蚲 /8Rk S̅%'4=<0 U۶gB۶,+v3.PٶQUtuHy@فFj,e8O[Io%|?'EDۚR}[L'5鴿ur= yx`MFh;<[gLn.,_XWH]ɍ;vle}nvl}QZ0rh>5P!gYdT3o0ϜTU̕9u$;\Z>5s$ >v]sCӗ ~u$?]oMr(C,)<}4 ل6sZƵNG{/P(`gJfҶ[f,rP 4-^8TX:GK6a{ˀm}]abe?Z lٕWWJ咋BfF'k'Z  2H*Yb{Ӎ?/u%^XqpEjn1bfA`jM(>VOrkWWs#-h@D=@ܥ|O=ݢ<^&] "؍$ȧ"F2Ru܍9Q=FsJxnk( v CzJCz18kQuz.ς@yY@aAө>ޚCg]7hM/]ˢw%em8^.]t a 7yčv|'={-X<AVOH_(pOG_9T_(mlRT[d2f_+oO $Čvq׬D旦ow_]o\{S&Pl>] @v>G荺mF]bGv>W7t/z ɨϫ Ǘ5vE:Ϳ9*5>)Pu>>.Ĥ#DϢcQSɭ IueMx Uj_Cw 6]PD T>{M]G WK>۴X-߇m (tښk{1""{I /KP2a wjV9 az2`p6jN JWIENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewshowchildpane.png000066400000000000000000000003331506556630100230210ustar00rootroot00000000000000PNG  IHDR szzbKGDC pHYs  tIME 26>hIDATxA  |XUK'ˆjɒth2 lWr$"Ѥgh*@D)9R "@@@ ~;DF֑PIENDB`TreeLine-3.2.1/icons/toolbar/32x32/viewshowdescend.png000066400000000000000000000003411506556630100224760ustar00rootroot00000000000000PNG  IHDR szzbKGDC pHYs  tIME ./knIDATx C҅tGE߉p!q"u(j b\L% 1u aNln /p6i9iz*{kSgZK\"̓1AJ94QSUE<%(9q+.)` 8t]!yYxjMj@ZW0%\A(yT^LzjzDP@pToAF#… %b(Xq,{Upo }{B4Upk* tWYc ȱLU88V b选 @N6q|ZZ8XgIZJda`sڇX\ /e%|{Wm/qSI<ېkQ5/=?ed1/,U Rfg3ޏK?{B{c\XspJQ?S;·{ϛxj J@%'<+OӲApz*ȕ30"!Tq[>[k.(AO'܁b2Tww_h+ ;𫝈ܥſݜEOLԈR5>>v|k$pj.bt͞| PMYyyV̜q+Uh\(ӊxc7pi[0kf!"݀5g0GAn F4 [vA{v oJpdp.0 ƆL,dwp*JU bzݏYac.H B$W1 S橚 Ѐ͵ {3Ws@XYo9%h4y(Kc͝(\#Es@& 0rdP$k+ham$. :ۉ].G P9AlhlevNCz4Q()tp1 RB I~ kJjYte!">.IENDB`TreeLine-3.2.1/icons/toolbar/32x32/winclosewindow.png000066400000000000000000000033361506556630100223570ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<[IDATXKlY~/sj;'u*Lgt !N= + fU6/;ӴQiLtAt"P eXy5#!t={LB|} 5 'BOhޯRq"1z3.xI[SS;M8~atHPkkr,[v!zA6Xb QbS8M" <{G" " <Flxx_ CKb1z1{O8V ;7%ۄ\#gm+D-H@66֛v`u5?5tG>"c dEE:6&޶*ks##gu1dsY!9GwcWDO&c!]|~H,#;&9]%rYp!@WWUôǒ{ Ϗ}E.>` >Bpxz.m4㫚42<6Z t= 85NyrA D|ԧFΎ"BtttHӆiۻ.ڡjAr:yuo\vP4M˲.4MHϧ q{5He˛L\f$,c2H&~D<~ݲMؖ0$I4X Ө"UELLW"=J%c`Du Q,u  ܄MA]x. B[8qmwt@ܾ}jօw>2@C|0=!P(ԎBa(;;\DD@Pч֭ǵ&3 S'8|S<nc؎od2HT'(mс"kKǮMS@X,4wz8,),e qߜj*kсP,wC0,X\q,G/?r9G[2KôNNDDRrʂi__,U\C(jތr Ls` ^y{{9~HDFb05JZ7+[^^[q`ip{Ku.ZcD$s3^@@Q!1bWηZn>{U=# A$lonBoPH&"&z$|p{^( \6뽷mt}.ߍwO;#r-(!V \{ !P/O==EUd ]Z;ҩ5 h'>3Ǐc쓀(es_./`B<D8QQR9pTD^Ft{@U{^PՍ]!C^jo8 `)$5IENDB`TreeLine-3.2.1/icons/toolbar/32x32/winnewwindow.png000066400000000000000000000024111506556630100220340ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATXŗɋ\UW{(c'fJE8(ʅ.ƕdq֍ &*BI !!CRt{\TwJ]mws~sU7T3P Xls)bѶ&;JF@zR2n!G<UC8'B!woP3^0 :bTƜ,*-JM sܯ%)WR0jR~XuM4(5)D~]/pImZӣPk^JG}짇xеg:`bx|0O>X nd:\|k_Љx-iR{8}n8/wلbxm8%͓g[AX>cyԍ\쑺f3~( t_~ Y}1oS)6,֙,,1Yx> AR?81{Њ3TSH*~PM3Mlm2^$u{0lI~bIEƫӎTxv_"ad ,VɭZ2[Tb$:ѷ\kͦQN}q=; sXƆKJ~ݨ$$YIlcVx(Y iͺQ-"j::F@MGUu vMDJ;Y,j뱘?3Bq99"2pϚ .D+Y;@F .A@0RR:I#ii-" XQ}u!b3&| PeZb4#?Dd 6!mA92~v'ZlʟC5J26*MyTaYt@=Rgrc$2BȠZs(ݸpHcna"f !FC2N8"6Ź P;vhKC<9YKF[\#B1?z.\<}ϮFJcPU=D$:#'N8M' Df/]] ";<{5g+yS ꪪ}/#* :뚜NwmlJ6Z c&uTIENDB`TreeLine-3.2.1/icons/tree/000077500000000000000000000000001506556630100153055ustar00rootroot00000000000000TreeLine-3.2.1/icons/tree/anchor.png000066400000000000000000000006321506556630100172660ustar00rootroot00000000000000PNG  IHDRagAMA abKGD pHYs  #utIME 1- IDATxڍO+EaqQlowiaORB ZI}ee+wcݑk3G;gy睙Lgc%W8lWT 3\8Ё+$(lD`4aI\`r|<+<&>c"651S<׻[ sdmj|h=ou ڨvQWc\8k'N`Tx.cֱvqǨ h$qwI [(tʹ2X~~cLM !IENDB`TreeLine-3.2.1/icons/tree/arrow_1.png000066400000000000000000000004451506556630100173700ustar00rootroot00000000000000PNG  IHDRabKGDIDATx͒AjAE_Uw d7ЕADGQ\ gBe@jSPCe]~m<h<'7)1̳$EDxm-3T+@5} ir+ň]R@nXdè<&[] Yu)`p:_dS[6N-j,t}RH¿+>HQmIENDB`TreeLine-3.2.1/icons/tree/arrow_2.png000066400000000000000000000004611506556630100173670ustar00rootroot00000000000000PNG  IHDRabKGDIDATxœ 0Ek/7(͡AcTJIA|%{H. !͞t {G!֨,L rDp=I+0  )efjJ*@D TlpqBջKEsXHO`&r+аU ua]40u=D,eJ$׀q Q@egjmXY l, c/É_ LLLp9Yԥ|*ýÂl#}|7@_߻pmR P Ï/04q`Ռ-bԎZ %*.M^xoݜ IENDB`TreeLine-3.2.1/icons/tree/arrow_5.png000066400000000000000000000015031506556630100173700ustar00rootroot00000000000000PNG  IHDRabKGD pHYs ,tIME &0NQIDATxڅk[e?{ޓĤibHҎn \cFaؕUEx)dPe]"]KS4'Yy&s< I t֜}}W<%L8aHvG"6:B+Wg *S %- G $ L_ﱸ;پAeN !oW^8E:( t$[:6WZ)K?O O baa)U XME&f=͎.xaP1@#X1$4 L\n$2,eCdsuR;bbrs4/k a+>NWOր*Tꘈ6[@rj.ζzƺshN\E)1q 78K~jAU@yFQ ڛ=TWiaODt-xBTļp{&"T0 ,R_m#M$M M6)XNg ˋ+'͉엗/zTPsIENDB`TreeLine-3.2.1/icons/tree/book_1.png000066400000000000000000000004241506556630100171650ustar00rootroot00000000000000PNG  IHDRRgAMA aPLTE@@@@tRNS@6:bKGDH pHYs  ~tIME \m_IDATxeα E=- 0;2EI@ &` $ A;qyqt~XaUNꀭp:s٦l_IENDB`TreeLine-3.2.1/icons/tree/book_2.png000066400000000000000000000012111506556630100171610ustar00rootroot00000000000000PNG  IHDRabKGD>IDATxڵMHTaޛ$cZMSJX2"jW*Z D-ZmEAiZAE`iLR f7_ Q$E89=qƷ O Mo FnM(:.ӡV5iBp-z0]^r(Ӧ且 fe3ۛ lGJ)(`hJAe@v09yXy@EB˾i^#cp1֊΢ea{]:]AyCy.?$}=)f?xǓW/n3pp5Cx+}\SJ$sdJMW%<PM޴Q+WLii=0Ǔn}&R9mЃI ]C;ɾgu[:H$PJ R233]] -~~+yAi@xpb_QU*B6L˄Dg:ގ)8u;ahKP)ByY8 x{{CPW:gd^>dBh&ϣ|%җhɋIm˜ 6p{ 눊@5Ph}堅yegtX0$h Oz}3=&}IҢ\P UX9X?[W6/'lhs=HCCChF5u( 8ba@& * Nj83s10r20022۝C xyBf< M7_b $Zi1r2p2(++13mNzzCpH 32030|< 60230J09h0wf@!,t3 O3`yX?202nеh. >=b<3C+_$.103001"4'}dI?=pk X^1W/0<8pvL@ ;lxA @6Ggqo`n@W1qa@>! N1afgX<0?}fA(?<&?#o x e03\xᳰ./(V|}E@DH?#hݾ2O ?}f'-A3 ,緿 7oas! 9}.T5@ =Tf,7o_fx×o~]𗉕Տ aY^^nIVUU 9pǏFa? `(Q.HIENDB`TreeLine-3.2.1/icons/tree/bullet_1.png000066400000000000000000000011721506556630100175230ustar00rootroot00000000000000PNG  IHDRabKGDC pHYs  tIMEjktEXtCommentCreated with The GIMPd%nIDATx?nAH,9E#g(@p 9Gj'c?ޝG)XIi>o40j}\01Cc9|Q/vr(I$YFnȃW ׀fj6'aHR!NO&|L9HS kGU_(0ayM<],x|r!].IN\xw:V `we4|g)77xqR +[s]AFlmj<Ư@'ҽHKQD2ARQNY!k@iCp~₯IBa 9 l`E.f6zzy1͈o`Z-@c]*utyXYC~ _bH*UHfNdTQsW}"}+ҳ]}P`&?B?_BIENDB`TreeLine-3.2.1/icons/tree/bullet_2.png000066400000000000000000000012501506556630100175210ustar00rootroot00000000000000PNG  IHDRabKGDC pHYs  tIME ؁tEXtCommentCreated with The GIMPd%n IDATx͒nAFzsUb/qEJx4<@"***$'JG@BR D@+o쬽ٙ@&"5|կ_NsqAy_/J$膒 gBwgO?ÿn=in&)X)RQ8#;V>ozyX_\}T[V.W(S*p4RHcg6k^Q)`tma7(Tz ta-$E ux0N0P.iZ:_':c{lZx)R C{Mxίɤƴw)YIׅ6\,FI{>o@vQ>j6u!o]qBiq`b?Oed ^H$

     F1  F " @aC/Gpr000r10 0`^1a8ph:P"A %^`` S @@14%$@ xjPM3 g 0f6Or n5]ex4ؿU |i X?=L ^5S(\ `N~` /, {b,HIflb47Ź QU!6IENDB`TreeLine-3.2.1/icons/tree/check_3.png000066400000000000000000000005341506556630100173140ustar00rootroot00000000000000PNG  IHDRabKGDIDATxœ1@]ҥ!'x4mt)-v-Ij+lC x"Aaa_53r, |(=ϛ70`[vöm|.x<rb)%M \Rk6i!23mۢ"c\u99eYvF4MTUp}ǙLZH(0  ~7 Bk}߳^( ZfO~P"mj IENDB`TreeLine-3.2.1/icons/tree/clock.png000066400000000000000000000020311506556630100171020ustar00rootroot00000000000000PNG  IHDRa pHYs  gAMA|Q cHRMz%u0`:o_FIDATxbd@*o*?}ߟ?^M 9{;8ß=p#_ן|O⻋`zԒW6&~6FV0ccc\@ }}P@LE) 6Ro~2|zEk@'@1XߞnYj" ʲ@00pꙇ r@g30:|*r''5O ī} "BtTp;eN =SqS { VE g&FIENDB`TreeLine-3.2.1/icons/tree/colors.png000066400000000000000000000015311506556630100173140ustar00rootroot00000000000000PNG  IHDRagAMA7IDATx]L[9f8af"S$順 +5,j,e]oQ4&S/0F5`ljeS L@Ӗ?/: ,{ox7HG/ QUW/,3tn! zc;ø~L"kY]`<ޓέ𭊲-'q,XZ2+ \%ăؗr_-*G{'_AO>js֋쩨X-U2`٪=w~I^'#DZVޘ>=խ(J# Yuc] JUe͇w6YU(  c#<4ǯ"yq8%Eުc3Pе ϻi 2@:e`ZXyJFl::)DZwNAσ  br\fTs~1$b֩d7H]d$?`b>҆m!vr&V#>JfIbo"4}/\U[ĄjͱI3 $UAA4tk#@QLkJ dNΞ2EmH!gC}^y۷YN_@%X>7.Zn+wXk/7-h 9wbxq`r:=zў>`6&~*̇Wߴas7R9ziP9`_ nn\#ZtҪakY.L7q~MCH IENDB`TreeLine-3.2.1/icons/tree/date_1.png000066400000000000000000000010221506556630100171430ustar00rootroot00000000000000PNG  IHDRh6 pHYs  ~tIME 0-I!>tEXtCommentCreated with The GIMP (c) 2003 Jakub 'jimmac' Steiner'3XgIDATxڝQ"Aie5XM430301%|354SGCCA`qٹ`]:Ɪ1nzf @@ۍ&o`0PJ}&|eZι7r[B 0|Лf4$Ip8lۯ׋6Ƙ,NrZj,.w/MSzxIDATxmmHSQ7qHm RrL@$6X.& DTH 4)Bz%?L$ tsnW79w6s8<=@  ET z}Vd\ńbMrr d񢄴suu?'x'}NP(PL )))h}3Ei>L"%%|G@;#3XXql`jjl tCZ=#oڲƚۇ<hlvrMxd'j{ hD5f D(,,T?bpR ? ;/H]}։NL ]gìH$Job9@v7n>+ ݍEd21@TjV/`́W˔cb.^2KEQK<,;<@/yޗy\~"&O2a'zE*Njo[0 @wߌ1X|6hƣ̡v$ESF3Noe/~&:z̟?oN+{ _a셯_1|:?>6V~c߿b7?116 s QTŘ!߽RĘ=*rǎ5C!Z @C!;++#3#';!^.W@O?  @; 4Xr`G(a= .]@@^ tf`|i ' Y_?>'v?A O80‚ hׯ ?;Û7؁3 LL@W`@~@Ac0?Pd 4ϟpb/^axSEׯO@ Z`F_??#Çׯ} @_7778l (Iׯ3 `2  IENDB`TreeLine-3.2.1/icons/tree/doc.png000066400000000000000000000005351506556630100165630ustar00rootroot00000000000000PNG  IHDRagAMA abKGD pHYs  ~tIME,"o IDATxڵS1 0{_c |">Dl ^qDrq60v3|#@pC BkM0PUUV$ ,¢kRJQ;'(ж-y8(rJ!Iq~;Ƙ}4M7n^rɖ|8"(]g7珸Ak}ЁXW!a-i(Ng xn]D ~IENDB`TreeLine-3.2.1/icons/tree/euro.png000066400000000000000000000005161506556630100167670ustar00rootroot00000000000000PNG  IHDRagAMA abKGD pHYs  ~tIME  8 IDATxڭ=@slhmH&SPr/`mmhhXX"%7Xp EUUueL[&p1B-MYȩLή-pNc7VsGHҜ8ω"o1d` }/Xy{,M뺿T[P=i01"Is $oz'm>IENDB`TreeLine-3.2.1/icons/tree/folder_1.png000066400000000000000000000005471506556630100175140ustar00rootroot00000000000000PNG  IHDRabKGDCIDATx͓MJA .\(эQ"3i.WzvWQ*3Ӌt!` n,,,!l^!rT_e xO9j"2P@6N$c*$I/V=P<-9 ߢ/6FKɚ_ 4T5JOO7FdJvpш}" T<<=أKF͚N\e!nUPW_K{G;8|11>S-y !LdO q#ZR|]({Oϸ\|қݻEIENDB`TreeLine-3.2.1/icons/tree/folder_3.png000066400000000000000000000011461506556630100175120ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  ~tIME ('IDATxkSaDmbJk⤒E!\]Dpܬ (JAjH2钥DJn%ښVWo?roס&&9pR E 9-X56hZ'ϒɿ1@"'9Z0l^+V6$-,MOjFd7{r)2K;`o! cyJGS3nmZT,Ɇ%m_'j:^Z٬S/>U qnVވ|K怡s<|rfQz#!hMJrRU;yl;.cC mWsg2`0*Ț\ گ,9Wx;GjcæF؃l*`@ mhDJG?VL4 +|6Uk, (C[jl*`*J=ݰCcsBhh}c {w2/OW[GXW(w?xufe5:ICzcs*kGPf{JY*PB5~lϳǗu0@ ׮Փ1gHzLk0 ÞwsDt+Rǥ<+ߩxr6L@0H47"L\j2A;]LY[- wZܶڈhrPߙ#{zj)멉vw'H<>3S TF)V6xZ\^Kmn_\ أ|Bg_ּR {B+_C{3G?=aYewp~eP*t-?Y1 9IENDB`TreeLine-3.2.1/icons/tree/gnu.png000066400000000000000000000004201506556630100166000ustar00rootroot00000000000000PNG  IHDR]RgAMA aPLTEÀXXX000I>tRNS@fbKGDH pHYs  ~tIME&  aIDATx-MA 0 KV Y#d;l)IC"*WqUwNn@LK3Gp8x)dSvl\?|]/Lk@IENDB`TreeLine-3.2.1/icons/tree/hand.png000066400000000000000000000012431506556630100167250ustar00rootroot00000000000000PNG  IHDRabKGDXIDATxuKa?Ӷ֚y( 1P.MEtUAAAP!AfeT +-cXM9;}Xܽ}>V')@j>u=mPY7MID[n$`m|ey5,jer 癛ri-v3خ`& X%DZ56h8#ˉ;|ɩ+)]m{PŒGx4@ZPZZ⩨j :9},p1‘o;?:{`y ә̥@E3,G_c~q9Qaq 5;QY)CBaA{Rt Х @j\vɴVyH%[/_^yD1 zS]G:vxۄ_:/|(% #CE+|(zˍl%en7[ jȼ :104H!qT#::q S)!ZceR[6 2\SKWϞ*o.eeb[&:e]c,RD7/'p~6Ex˭6 ?yٕ.h]p,k3,'Qw'NeHUb4ޓ?t:}~3B"ن3uxD\~-k_G!P;IENDB`TreeLine-3.2.1/icons/tree/home.png000066400000000000000000000011401506556630100167370ustar00rootroot00000000000000PNG  IHDRagAMA abKGD pHYs  d_tIME +JIDATxڭORQW^N6J0-$$,D=V~9Юf1-Z-\q 炚s\?wO!Q(D&Jrexz @.CuR,ST VǟA$Au,jMA>'2x<$IJE 4M"`p1xP(r暄Z-6FMh6J<3 lfɓZ ,!NG!BuYtIp$*`@4e2,nQeGrMӰ,X,=۽F8pVq ?z=^/$m|s<0_( nNnC'g6ӿS Gǒƻ.|d;;|;ducR?_{16IENDB`TreeLine-3.2.1/icons/tree/lock_1.png000066400000000000000000000013311506556630100171610ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME 5%_tEXtCommentMenu-sized icon ========== (c) 2003 Jakub 'jimmac' Steiner, http://jimmac.musichall.cz created with the GIMP, http://www.gimp.orggGIDATxڭ=SA"\6jL?! B!6{E fbt%9ALq<̼ꏀ@nG@ ?JWV+ q8vle28ٶ-zWfeez]t:e۶ wh\z A-tBo";9bo- /4<-NdJKESܐ 1@4]_4w9 r:k".)a ֆDk R 3U% åR29M7 K,EWgX`z:Cz`:=sza(ИX|9O_  ΤZdwIENDB`TreeLine-3.2.1/icons/tree/lock_2.png000066400000000000000000000012651506556630100171700ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIMEp9tEXtCommentMenu-sized icon ========== (c) 2003 Jakub 'jimmac' Steiner, http://jimmac.musichall.cz created with the GIMP, http://www.gimp.orggGIDATxڭkSQ{ojb%bBAjLKA!.wC@;!"HԡB$%1E=p}x{΁c`y^ٌ{m4L& p uMJ%m꺮<\ VGnwf?jiZYEdMD}9F#)[)^am5xbOJW5Kkʱ5غr417f!yMؽs M:#hL|O_I͋pw7>b#1q% 6B>`Ypf6Q$bɗ>"!<+{Bͼ`HD )lv(Ixe ,[§A`~J:C:=WKcAmc1> @Ϲg DVIENDB`TreeLine-3.2.1/icons/tree/mag.png000066400000000000000000000014571506556630100165660ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME %;DIDATxmKHTq93י;(5%hIndP$UPѢ]EhX M(BaP9(3}}:$I(8B6,ƽb?"7ߧɲpl [_6Wn[Ho%k/mCT"bB>_"hKw4{`_he߯ގx[J<:in|>nv{DjjFw̱(b]Q{NۺUH}cff>T6Ic]Qש3۹#~2ʪJKfKP4+W>s}zE:P԰yE O?hs]UP]G"WH`IENDB`TreeLine-3.2.1/icons/tree/mail.png000066400000000000000000000015131506556630100167350ustar00rootroot00000000000000PNG  IHDRaIDATxڅSMh\U=7ɛ̏3d^Lh bK!⦴lD(fh7PA20)E:4M4y̤fef޼h,spa94exyIƿ/\1,SCC}/vJeKKt~ż&%Y5С2tJ8ՉLOԧ:HXvp&3HPy oGn. }`33??A^`Dܶcu 焵 0Pt)WT~{ʕJ&9pm@J uPHHvHiB}ưu5Juxу6R R08D^$FDR='%L&Tʂq,,1?_D@a 1_˴`:?W2U.׿u3xtLS _]-_v$R9XHngƍSF}?@17(.nv1v. `jbqViΝOkޭS_Ov,f|W)W_Q IENDB`TreeLine-3.2.1/icons/tree/minus.png000066400000000000000000000003671506556630100171540ustar00rootroot00000000000000PNG  IHDR;֕JgAMA abKGD.p pHYs  ~tIME (tIDATx펱 0ϑ%rM,[E@H4tĊo3B\N`DŽBlV|b^ΛEVDQrc=Yx1wpMDMb[;!:*<}3IENDB`TreeLine-3.2.1/icons/tree/misc.png000066400000000000000000000021611506556630100167460ustar00rootroot00000000000000PNG  IHDRVΎWbKGDC pHYs  d_tIME 2IDATxmkTWϽs7o%1h%ATJ]d";,"` "JwfQl)H!EHB3N2?{vQ=Y||8f0ƾ Lz7IRʿ9Ǐ'rSsl\jll[u<,^og0h4~ɓ'>KKKzju.Q۶1Fu!J㜶,ijjjϟ?]|9[׿jWGGGO0hEizLFs ($ˍ9Mj͍---JrR! XT>p8J)bG)j_?~AP(\pn)%0R qc|뤥IENDB`TreeLine-3.2.1/icons/tree/move.png000066400000000000000000000003301506556630100167550ustar00rootroot00000000000000PNG  IHDRagAMA abKGDGnKl pHYs  d_tIME *$ssgUIDATxc`C1NH@3A e+> q L6Z&tR a$S3P0+ \@rLqf"<8iIENDB`TreeLine-3.2.1/icons/tree/music.png000066400000000000000000000004201506556630100171270ustar00rootroot00000000000000PNG  IHDRabKGDIDATxұJA/EJ! lY-|!Vl6i¦Yfw.ws{f qϿ 0A=\saW8vT6zc{pb.?" #<`RRF 0{,5K$C~Z|N/*'X:F徟VedE[G-fJQIENDB`TreeLine-3.2.1/icons/tree/note.png000066400000000000000000000010261506556630100167570ustar00rootroot00000000000000PNG  IHDRh6 pHYs  ~tIME : D>tEXtCommentCreated with The GIMP (c) 2003 Jakub 'jimmac' Steiner'3XkIDATxڝ=K\AsZDB"MJ)@6BU 4VVY6AM ]A Fp\{ubf05S;[QzlktԐ,(mۺBwo4߬u !)j(~ty_7$Eńt*O.?< /=,+R.V :ؒTŇz\i|}${s3#HiR23&‰H*:WHzT;x٣R!J{ P]71%f0,yֱ[yXV$ Nu]Ծ ",BKH9"@B՝'p+HU*ٌV(qF8im$˜ݒeIQ|; !\$Q=z^ r&DeVBl"#Ya@Ņ VHUĂ H(gAZU\8ܧ}zy&j9R<:OHɽH gyx~t?op.$P&W " R.TSd ly|B" I>ةآ(G$@`UR,@".Y2GvX@`B, 8C L0ҿ_pH˕͗K3w!lBa)f "#HL 8?flŢko">!N_puk[Vh]3 Z zy8@P< %b0>3o~@zq@qanvRB1n#Dž)4\,XP"MyRD!ɕ2 w ONl~Xv@~- g42y@+͗\LD*A aD@ $<B AT:18 \p` Aa!:b""aH4 Q"rBj]H#-r9\@ 2G1Qu@Ơst4]k=Kut}c1fa\E`X&cX5V5cX7va$^lGXLXC%#W 1'"O%zxb:XF&!!%^'_H$ɒN !%2I IkHH-S>iL&m O:ňL $RJ5e?2BQͩ:ZImvP/S4u%͛Cˤ-Кigih/t ݃EЗkw Hb(k{/LӗT02goUX**|:V~TUsU?y TU^V}FUP թU6RwRPQ__c FHTc!2eXBrV,kMb[Lvv/{LSCsfffqƱ9ٜJ! {--?-jf~7zھbrup@,:m:u 6Qu>cy Gm7046l18c̐ckihhI'&g5x>fob4ekVyVV׬I\,mWlPW :˶vm))Sn1 9a%m;t;|rtuvlp4éĩWggs5KvSmnz˕ҵܭm=}M.]=AXq㝧/^v^Y^O&0m[{`:>=e>>z"=#~~~;yN`k5/ >B Yroc3g,Z0&L~oL̶Gli})*2.QStqt,֬Yg񏩌;jrvgjlRlc웸xEt$ =sl3Ttcܢ˞w|/9%bKGD pHYs.#.#x?vtIME 5)Zk6`IDAT8˥=hSQ_mS$\Fp4X7/*Aҭ drt fu .)h34$סI4-}ss=fέgK,=k܍YJmrnP`[)޵Pe='xI|R;b_d < 3=AX,0aA/?j+$$OIRqclA\. @zG K,@PHO@>CVsZ<)k;q$#ŏS{Q-x]>N!8d|z:3S  xMMﻗϤ*sXdI<IENDB`TreeLine-3.2.1/icons/tree/plus.png000066400000000000000000000005771506556630100170070ustar00rootroot00000000000000PNG  IHDR;֕JgAMA abKGD_ pHYs  ~tIME  ؎ IDATxcdbĥuw__ww# Xr[OJ4&go##S514 ,L R"| B W=gh뙅pp;ӗ 7t?l=Q$>Ȱg. bda```s:J brJGoO_#./ 0l\f٥)IENDB`TreeLine-3.2.1/icons/tree/print.png000066400000000000000000000011111506556630100171410ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  d_tIME  7dsIDATxڭnA%JOI&!8e\˼}^:"PHMb)9zNm$}0""y^/y\.ur|ܗO? #E jшt:r f(QǕ;'ɐ]q~γ-$oMl?nB"Ji:l6x<'H&}>h!P)t]G ^a0`g9;B*| @q0M4X,m7"B\_/V6+zߙq~BYIENDB`TreeLine-3.2.1/icons/tree/question.png000066400000000000000000000013521506556630100176630ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  #utIME 1q,(wIDATxuKawgFS#aFC:P@iUܹp^Z¶pmY,#$hS"[:::;-tF*=p6眗8ú$$BTJ܈JV y*} ]XS]lH4cjTRmPw ]\16˿ [|]uлRXe#L_GpDXZfAENxc 0Yc_N=M$d -8~G`;@Q#WP0*pa2, ڤw vE#0t Iȱl @h]20Q]E_Bрg9h39tCKajݽ-ucQ%\Cj| B&8FHeD!F#_EpHʚQC Kmk̲CbQx6G$Ɲ c[{s*^S9. Wnu8?&~lډaڧ%TҼe)Mbmܛp;iCwB.~+b<|ǂӂfvKL-YHC. !e1]̕2ekbڸs;*IENDB`TreeLine-3.2.1/icons/tree/rocket.png000066400000000000000000000007051506556630100173040ustar00rootroot00000000000000PNG  IHDRagAMA abKGD60 pHYs ?@"tIME .NJBIDATxѽJ`IZPEEp *HuR+~@up.EqނPAѩMqЄJ۾pec 23z,ap]4Xu|wVɗhj ap|yy6D ,Ak5 u*N<11^k1X,}m'3H@
2 s-jLf. @n*ENz acLஎJKd=lE3> F"&fd{>1@uaX\SLԶHRIENDB`TreeLine-3.2.1/icons/tree/round_minus.png000066400000000000000000000057541506556630100203700ustar00rootroot00000000000000PNG  IHDRasRGB7MS tiCCPiccxgPi CD HI$Q20$L "AD\]"QP ."**}xWO?UOU x"')6 ug2  VNj?XKލHxI<.nQN[XnWXrfZJ v\a:W8Xȑ8Q1x_.GʄBSBZW6k57EyZ࿝%*|qiq9X}{m;`)^S; e7=k,@)'.h@@2@M  oBF A&@>(% 4Vpt2n`<0^y,A uH2ؐ5yBP@<(ʁvCP)TAM/92tB,7F`L` Xfvoc8 ΃p=| /÷X"lFBhlG riE~"@( btQ(WTJAmGP'Q>=jMFˣuh7t0:Ga`X3+&ac00CI`l6[=Na8%rqf\n7[‹xo<_owK `E'v*q"B4'; Mr IH'HHIodٖJN##7ߋĸb;Ī:Ć^Que#%RN9KCNjk;Go?'>& A0H(h!1CR5NT.5zz:ICh4@Jc,=^H>HJKJn )` #Q8e|R+*5,(-'m+%] &="Q)$ _S,JV[G6SU99G@#yX^[W>[BB9EbbbMZ)NL $ӎȬ`1]ӕTX***m*OT lh2^y5%5/Gxuz!~E FN4ˍjak5m4S45kaZ Zj&ڱwt`S8:CЫWVկ%fN1R)ᕌT4tׁ2fYAۃ(7.=D8~HPYUVYR*jھFfoa#GZkj k?;Υ^XƱ Ǜe ?=d,\̞ ;ugǟZu[m/~ eǙ޳쳭ZNk/:vwv BιnMW_PCYuqR1'{7>|~OUׯ9_o7,nɾyVǀ@m탦wt5=fgf={ݿ5vdh4`Xؘće44c4s~y/^&\SϚW~ysޅu O%[Z,x/A2?a?U|rD. r \@"D. r \@"?vnVccgy*4`|zTXtauthorxsVZ!P,FIDAT8˅KHUQ@?9y~,B B8rJ&nj'Xgd}xR̦{ .غ I8C  I4L;@BۂI\} o̸ <OT{YqQ&A|0)6,2n PKUvˇcPnNQe.[vX'(% 4Vpt2n`<0^y,A uH2ؐ5yBP@<(ʁvCP)TAM/92tB,7F`L` Xfvoc8 ΃p=| /÷X"lFBhlG riE~"@( btQ(WTJAmGP'Q>=jMFˣuh7t0:Ga`X3+&ac00CI`l6[=Na8%rqf\n7[‹xo<_owK `E'v*q"B4'; Mr IH'HHIodٖJN##7ߋĸb;Ī:Ć^Que#%RN9KCNjk;Go?'>& A0H(h!1CR5NT.5zz:ICh4@Jc,=^H>HJKJn )` #Q8e|R+*5,(-'m+%] &="Q)$ _S,JV[G6SU99G@#yX^[W>[BB9EbbbMZ)NL $ӎȬ`1]ӕTX***m*OT lh2^y5%5/Gxuz!~E FN4ˍjak5m4S45kaZ Zj&ڱwt`S8:CЫWVկ%fN1R)ᕌT4tׁ2fYAۃ(7.=D8~HPYUVYR*jھFfoa#GZkj k?;Υ^XƱ Ǜe ?=d,\̞ ;ugǟZu[m/~ eǙ޳쳭ZNk/:vwv BιnMW_PCYuqR1'{7>|~OUׯ9_o7,nɾyVǀ@m탦wt5=fgf={ݿ5vdh4`Xؘće44c4s~y/^&\SϚW~ysޅu O%[Z,x/A2?a?U|rD. r \@"D. r \@"?vnVccgy*4`|zTXtauthorxsVZ!P,F=IDAT8]MHTQϻcԖC L Em`EA-,I- "- 4#B(16Q2R"iTqz<s߽gI:ܱ ,ZA> <?oa.l p`4*=S.plaw  @#]؎y`Ӱ{ _Ůjj{#0g˰`:@M`g Wkyk N-,4TUgЩ VcCs|_` h eL _n1J ~j89]P2`ܙɿkpGY-[ TWaH$( =%<#km/nL `36>;4̶p0|-dP *~DZ$7~t } % wɗC;S?OGT_q?K@v#犓elI3]GT6~&6̧2;'q088cfl§jdMj'kޛ2>_/V[ IENDB`TreeLine-3.2.1/icons/tree/smiley_1.png000066400000000000000000000015051506556630100175360ustar00rootroot00000000000000PNG  IHDRabKGDIDATx}mHw?keVW텒T9j!aE[kiz5֠A/6VfEO(9{_?zjs|0pX3q88{  >8tjl5PnK淋!~?b}ː,VbIRP2db'9wj_6(3˿9]vjϞB}xV'9R\7pѪÕ[qfIR(?Y 2(;ށ$, IqxbӞGshNRz8Ǐ젷@-@pEx޶C "ϾΈ*2|dgxr%$BVq W[?_p9>C$G [w\nk[%'ddBx4)!0mM).6XL,, RXE S018f{Wa@.:`MIENDB`TreeLine-3.2.1/icons/tree/smiley_2.png000066400000000000000000000014561506556630100175440ustar00rootroot00000000000000PNG  IHDRabKGDIDATx}[hg/(zcT%BQVEJJ/E#x^I{%ZςXZ,(DSh6"Fec jL6{}_/JkaxSZw2&UZP[J6n&JW]':5Ps]Ќ)Af`0xG`51i>ΏwiDXxABH7O*1ogui[w4o@#gM3hߍn24EH7 >ml* 1se(f;w <}UĵȺEkQ03C{ ,*]|蠙L^qI#z{{9r _'Vzy& gμD8c8~oBz"n/| e3 Mf<颤N'Ɂ#(?'\W~6"D6JXtPC@[u{O4 0pSMזyu%=MuW]ZL6ۍ!?sp&Vր"O'XTјKKnqwN[f>,>-fVkN_5PRh$H4pߧǶ ChzKHY,)^8>{3]Um!iX"Ć='kCp8,}ocIENDB`TreeLine-3.2.1/icons/tree/smiley_3.png000066400000000000000000000014531506556630100175420ustar00rootroot00000000000000PNG  IHDRabKGDCIDATx}khu?˙[@m /hQHxA(,`i#'Z"^E  Q --Jps36 Ιudzs. oE \:?=Ƨvxoֿ]#p\/$ǁ\e0*T8aXX *&Jrȯ|vn2d˛|YNRpÌb* h^]ވUAo>p-K؈2H?aX8Ћiא)1*p0ީcqZ־3W}M`մJo8X-Բ6nYseto@sMf|`a5%GO 9to֊[f}3;hϷ}x;&S~wu&;ˁa *D2~w|-8#E+ ZK KZL/VC"*C4|RJ>f(,d(2)` V/oťulZg(24X8gEP¥j:" *!CW7W=6pZ/?o_켹e>CM}C'#d8#%+ΪxieIJ#.yeutHOxq4ܾeM -UTW}*FҜD r%/qIENDB`TreeLine-3.2.1/icons/tree/smiley_4.png000066400000000000000000000014131506556630100175370ustar00rootroot00000000000000PNG  IHDRabKGDCIDATxڕYHqߢ4-Z9e{$Qe=EAbiKA-QBDEeeTЂC4VN3||ۿ,:psϽp^9@)pxWoq~lQ]^-? -z9PJ,FR{H+ AI8~_jyJ_åSZaDca$9 [`jm`4/Jk䓦`i/z8#/Ig˪ةl]k&o_> '.c+1?+8uoř/ wWp#H=JXxs#, `,T+ʌu>S  %LBR KCX1ʤK6Mn0q:r<#LU[TzmFoъ#68}S[Oe~SnOkgq^g{ی MKw!E45)P 7P$>WbBKU$tU)^gű=bl$1/&'cF;px HrBqdbAA|l.ą(n]1gF)H! CiysU#`ߞb`y9nR$b AwMZu7>.r@`8 n BIENDB`TreeLine-3.2.1/icons/tree/smiley_5.png000066400000000000000000000014431506556630100175430ustar00rootroot00000000000000PNG  IHDRabKGDIDATx}{hq?y_̑3?93#D\ʥ??-C [$E[lss9sYY9{{Èo=}zϷ>7@)P UG,+=af6qnQ%2U;uEHr#;>sJ^JP~C%r׬j%1tnd}8]v-Ѐ|Jr^}4h>ѠpVzl#D4˕QϠ?6C\kr$0C1azslL idyJ I[G3(Fgxn e&fMV 3 v{Ȃ[k#sQL0P m~ъX|.Z @rⅅÓruAN,aNڸPgZ0\Bg˚|,N@$j$ {h'&x-/P{ow$fBO$!T,KTWsZ L32QxJ9$ItE˷߸x=ȫKF08DDcIENDB`TreeLine-3.2.1/icons/tree/sphere.png000066400000000000000000000013701506556630100173020ustar00rootroot00000000000000PNG  IHDRabKGDCIDATx}͋E]U]==;;cv3fCED&bK\O<"]='/ l hf=U5A6w{ǃSPJ!B !\E8>U1_0b%A T:be lzZ0R@8 ``cgscrRfK@a5mC#cF  OD- u1A/Я9q3 "/cx>߿ _|d`` @= ƿ '0;Y%A}"@{N2~}Fo#P3Õi>[ha@}C|n+>L?ڼçmw2, J:x?Y"X Çw0l  JJ ~}'DR<?@(zȞ 1#ïMP f0=bO_93 oB :L @5pO4\`hՋv_  x NdP>05 :+Pρ'^&9'{&E@b!Ru->MID|~~8ؓSlɠ+T{EH #k\/qރVк#Z[cL /YhmHk)'VBtEXtCommentCreated with The GIMP (c) 2003 Jakub 'jimmac' Steiner'3XIDATxڭ1HawީX q  Dt0Xh@ڵ8.v(DұJҒ ikXk;࿽{ߵV QTW&-,p͝]<ϣRP.hxfyxY|vjJ, c6BGfRPeYr9`d2>> R* quPѺYPGh{1Ƅ*D{{x=^Mbu u]z#Hx}{-n2M4D>V풎,;-4|ZxjL:F\EE"p0d d N"K/gu6|z:!2y6cIENDB`TreeLine-3.2.1/icons/tree/term.png000066400000000000000000000007761506556630100167740ustar00rootroot00000000000000PNG  IHDRagAMA abKGD pHYs CfStIME49^gK{IDATx?nQyX(J qw@ hr]:*@ e߿ŋGO+FfF̌hж(]ɢm[1FrSN)Ri[6 UUQUr~Hu]}{~wG_>_npǀp~)A1+sF"Ὗ:ݚ{b C"NXV«=.(po a '3fᗽ菞פ) 킍(_="4Yf0tq8!L fQJ&Z agݧ'tIENDB`TreeLine-3.2.1/icons/tree/trash.png000066400000000000000000000014121506556630100171320ustar00rootroot00000000000000PNG  IHDRabKGDIDATxmOOSY{R;PEl`bԡ7Pd14nܘc\zWJB&3$#Q'` 4b)TiKioV$>{-Bq00 ,"377" m;B$ ܾ) 7"%C3~/8[)_C^w?<|tb` ٽUx|7lNzzzzN'f^C'hy;¶LAm @,#ځN 0B l܅bXl]Fp-4iȀBk(¾Fb<rqWV q6-<K299A2fa!ͻw)ٵR'uwwP(DG]]S*'Bb US5TM71:zXV]X\|OZE5TJ ֶ~*CCqO\t_.'q]~(7 #<(HIENDB`TreeLine-3.2.1/icons/tree/treeline.png000066400000000000000000000023351506556630100176250ustar00rootroot00000000000000PNG  IHDR szzbKGD pHYs  d_tIME ,P6ajIDATxڥoTUϛt F# jEDN[H [ݙvo02hQ"?"/\s1wLg=73{9sV_wTIsqMXzI;N䌨&wcBw 9D$ίxgYK.^ O+7f"ql0O:航x!uUYz|(2<ٝ2rjAU84OOϸQdYp/e_zs09Qk6c~%O!Qm;NvɴI%h>&x#Ÿw`,taŎv2,ӵ[ 2ܩcT&E c<RSlHӸ4S9b,$2^ j@diY7͚Q%df aA}Oq7 OZH&^A\7e&߂DPE;NY Yk_ 06\s)Ћ9ZN2 m ^wFMWA0⥌OJbCb2W*xR1}H8Ғut kz gȚUa S78J_؟uLV̉]!,zQ#cXY\OHV87R`kC[L2 y%9S%RW} 0'SՖ*ccb,Qn,4aZ[l.ׅ`q%=ȥ\П iMWB&Opeq QT,`h1 A^jo. TUn1\UMu ;w_v%9ƛz@֖ ;i] m̙ci;wWX1+R+'ԅnp۝g1 m0d٩7{u5r|TU22.: ~CAǛm=Tu/:]#}ܯvDB/(++01/Pk0Q1ՂFڅ>ѝ\?,fwfM<=ϜsgF"Ο65`>P 4^b=RT_@,3߆oqU¹ZLrSk<7>xm|%?X"n6ʟ`䧆U!S" t!F{x\9}%(.{%kƝ?(6SCiü~ÿP0;6Snfq2=ϯ{9ND pu*-5Q$_@<H%{:l@Q#_úE̛n:_Wrv(3xRNN|50rwO4s1ҕ6֜|6-J^;@<4L$Z 2˒,BZy2#9Ry;oYH9b `fQ#ۉ;={XZ6#y *^JaO1Ql/C.+؂}9>;+7e_ٮJ@Yw N jmQ @& S&d3 q!n PXe,R+ J ?&±Ϸis xۍ8J\tsoiu5UUҘKWxJi&"7}VG!7M'24@dd Q1'X)CJ_u2}uqzL^a1Wʘd7ђ2 PbQJ˯կZ&S7yUD p WUUIczb=w:IENDB`TreeLine-3.2.1/icons/tree/tux_1.png000066400000000000000000000012571506556630100170600ustar00rootroot00000000000000PNG  IHDRagAMA7fIDATxOHq?ݦ:٦3ԙ!H(CT*T(bxA.]*;-`D0rV\0ݯ"&}>ϣ`,SUU^cnnn^ӴQGi3Ųh~8>jL3-ޒ=9p0F^aiGjsp_k\`Vr}D&<(7`:32b6n QIfI-`dffN~)z*%Ru$ ;4|ɉDB*.KZE` ۥc!H&!X]]%/\v.: Σun+, )\N'"dM OPftt -# !4$Jhq7Jܺ\lwaK}I$Wd~*)/Dx ݽd2 jtM %mYsl0 7,|$!"e yϻRS5@9{By IENDB`TreeLine-3.2.1/icons/tree/tux_2.png000066400000000000000000000011121506556630100170470ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  ~tIME ԻsIDATx͒kq?; A5j!'+![* nVU'$,6EAWB{rK~.^Fq?$K'@2 @h& 3C2prx( BU$pOK$ EQ, MwH#0sgQU˲T*E"H;5z@ KY]}I\&LdV82躞qbxG^xږp O9zJaGwĒ]bLs5`"nL$n;Džح}H(x[Ӵ1.b`2(,\yGSx$觯_jNcA!jCaiYVVjf~dt:i4 ,뢪fǀ/$o8¶my}ХRiYsE}/IENDB`TreeLine-3.2.1/icons/tree/warning.png000066400000000000000000000014511506556630100174610ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME 42 tEXtCommentMenu-sized icon ========== (c) 2004 Jakub 'jimmac' Steiner, http://jimmac.musichall.cz created with the GIMP, http://www.gimp.orgqIDATxڵKHQ7yh5Y&hN`3ce0m* "6"Enڵ(ZZ*{AH f3NY3sZ8-Ep9Ņ`&p w@7` x}\&QEȪjaBa ,"eBw |*& t@?,V-sqpK%@h,^`Q_q؀1h Eg:kkb1* 2__m y*Ѐ + S=Lp%7(Ֆ,@!L2>ljUDq |ɫqTھom *]T옦A&gx,p;/qp fnel%+O./-RZo+H)E0@vJ i=`IENDB`TreeLine-3.2.1/icons/tree/wrench.png000066400000000000000000000020371506556630100173030ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<IDATxbY --_턦}ųg&~}222LMǏ_ ~adQ 7WW[E`xAggLuu50{υ̻_Z͛XYky{j~NKEE@bfx=×o=93}gx |54DD}``exÇ/ w$O1r 1& A((9: I 14˗/@ ?999yy4~BHL0AD$D}dexm_L/@ʲ[?}ؿ/ܦQ _ L?Xra@1kk[ǿ^`GC_>*gkƗ€g`diʑ3 l322  ¿ r7NQL[}0G_f`} ȸ ^`6i9[03gx#KDpzZh-N{/ 0{~ax`a&IENDB`TreeLine-3.2.1/icons/tree/write.png000066400000000000000000000007541506556630100171530ustar00rootroot00000000000000PNG  IHDRabKGDIDATxڍAkQ? v"%ϽRu!ET&HqHBL! ) yLf a&h/Νt #ιxZrr㏘`__Jz`4J)|GD<7x|]?8mNT2y'/^me "vl<]~nݒ>]OXkf"B\>y+GA׳1s TZ= GAEDQ$aJ~9 f<16Fy5ιB[7WJ!"T*iWMιn1ft 0X-qsZf.03IENDB`TreeLine-3.2.1/icons/tree/x_1.png000066400000000000000000000003721506556630100165040ustar00rootroot00000000000000PNG  IHDR7gAMA abKGD̿ pHYs  d_tIME  1,{IDATxڵ 0 O9PXA20A J 6Dbvx LPPR!ޒcw`@r&:64BF+ oV<#Zq%)]1gUrh`L<.IENDB`TreeLine-3.2.1/icons/tree/x_2.png000066400000000000000000000014641506556630100165100ustar00rootroot00000000000000PNG  IHDRabKGDIDATxڝKh\uNΝ;4L f*t1 V("ZADNRRpS7"!5vFg2y8~*v98SBxt:=lP3 cf}BUU^UՑ zϾ0W >yWo bMU~鄊uevxq4x&aud2yvǧ$icrAأ}z֫l,mǛыTr̷?1-_[[anv7cG>z~%ݽĀWdOui??5#]Juw~pfMq| @ꌙJ^]S>Ck7Y-^ͫ%+ .v8d YkN[nW8/S3a~pq/oYnW{aܝ i" ˰nclݿ(27Hߝ2.q!KJp$[)+f ?{'gl6m( VPnȱG{ty4o$-xJ).$C%7(嫍}DEOʭ T⽷D9C5-`_nxZUoM>8ʽwIENDB`TreeLine-3.2.1/icons/tree/x_3.png000066400000000000000000000015721506556630100165110ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  @AtIME ",ᢂIDATxm[hufg/&K.hR)mjԂ-TA` VWT)*QV+} ڠ^&-6YldRsٰl6dgƇhM?9ps>6sy[q>\\q]pv+Vn!y\RƝ4|,%)ׄJ}AD|sv u8Ͽ`>;Ux̩M%rwfу6(~v/NCNhm;L>+ǩ0qx G}><ݷZEFтAT k5_Yoڄ .B3e&ߦ}a&B y#t_~?~ɧWp2;+՝:Х"iG&cx;1&X:O]Z, -7b 07ov G/7W#\weSY"W|i@(dCuH^UtmleA4{}g |xu~l,_4 gk5Ȭ*8>utS8TڞAfя0?-;vt-ѵs E2R)X8w.S[Ӊzݙp:}ݍdׅ$dL&S [SqW65P/~-;NĮd2ʆo6:+՝.GDEs `1X_&јIENDB`TreeLine-3.2.1/icons/treeline-icon.png000066400000000000000000000045251506556630100176170ustar00rootroot00000000000000PNG  IHDR00WsBIT|d pHYstEXtSoftwarewww.inkscape.org<IDATh{p?G6ݼ7!H ѦSσxӻQA^%S94p,'N擦 jހ&c:}Exg۟JŎ{`n2 O2~6ɚtn5kxMzkx>m۬cҚ`<1Oh'VzVMs:tr A^zNz;;|;w;3gYD'xGuJUqY2Coկ,2S-ٻ;GϘtt[/y sMMI (YΝ y wY։!5 *z?.}`JD⸴ff\76ה?p$m'd#!FV#"fhs̳|*{`(,bHFf@H;UUd +p|Sjʲ19PNEm}n!(mRw ĴHBl7|)LɺtmxW$ʹ~R1R:lYOɜ=Z9;Bu7$"?HAM.]"o n5c\ȥlO1>wNv:ΰ^9|.ҕ,u )Q硼bZ?1Hq[6?K7UQ Uq5Yj`poI @xì>|-Zz7L31Pe\e3p(*N'sƟ7W c"F b2U+%?qC?cEj)B1:^PVɔ1ī/dЋCgaVT /$C$Ua;M1BO??ENZNՃN$?oإ^m;RWםKȡ?A]9'RW׳@pAu G[Mޣ$s#TGut9֯ᥤJajBY1x>61mhCr0we7RL_3oCb=jf+m ovVć39-rqs[nxTq=ĚhP%Y۶5]g lw/3F4F';ՠR=ބC_M鬿'^s7VK#B1ىmR(KǑsO/cggv p, kG=QQjʗF$%8@`f_ΣUP&nk홚G/<`:: s5d i}F/4(l;wK&$mR\.$[5`DdqT٨H!,툏OvM*}>eYg|qNWKXU0抏[+Vط2"b/A_s&SF/Z?`9RrI62T/,pZIk0tp]fk 3PLA;5~לhT>ؿx2sdpG'젷Pw=hшm˗ˌnѥ|ԯqBc HVZo.bYgo@q]io-ڏK,q]$O tW<89 Lc']O6R:)Roj64 849GT5M:MIENDB`TreeLine-3.2.1/icons/treeline-icon.svg000066400000000000000000000146401506556630100176310ustar00rootroot00000000000000 image/svg+xml   TreeLine-3.2.1/install.py000077500000000000000000000373511506556630100152670ustar00rootroot00000000000000#!/usr/bin/env python3 """ **************************************************************************** install.py, Linux install script for TreeLine Copyright (C) 2025, Douglas W. Bell This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, either Version 2 or any later version. This program is distributed in the hope that it will be useful, but WITTHOUT ANY WARRANTY. See the included LICENSE file for details. ***************************************************************************** """ import sys import os.path import getopt import shutil import compileall import py_compile import glob import re import subprocess prefixDir = '/usr/local' buildRoot = '/' progName = 'treeline' docDir = 'share/doc/{0}'.format(progName) templateDir = 'share/{0}/templates'.format(progName) iconToolDir = 'share/icons/{0}'.format(progName) testSpell = True def usage(exitCode=2): """Display usage info and exit. Arguments: exitCode -- the code to retuen when exiting. """ global prefixDir global buildRoot print('Usage:') print(' python install.py [-h] [-p dir] [-d dir] [-t dir] [-i dir] ' '[-b dir] [-s] [-x]') print('where:') print(' -h display this help message') print(' -p dir install prefix [default: {0}]'.format(prefixDir)) print(' -d dir documentaion dir [default: /{0}]' .format(docDir)) print(' -t dir template dir [default: /{0}]' .format(templateDir)) print(' -i dir tool icon dir [default: /{0}]' .format(iconToolDir)) print(' -b dir temporary build root for packagers [default: {0}]' .format(buildRoot)) print(' -s skip language translation files') print(' -x skip all dependency checks (risky)') sys.exit(exitCode) def cmpVersions(versionStr, reqdTuple): """Return True if point-sep values in versionStr are >= reqdTuple. Arguments: versionStr -- a string with point-separated version numbers reqdTuple -- a tuple of version integers for the minimum acceptable """ match = re.search(r'[0-9\.]+', versionStr) if not match: return False versionStr = match.group() versionList = [int(val) for val in versionStr.split('.') if val] reqdList = list(reqdTuple) while len(versionList) < len(reqdList): versionList.append(0) while len(reqdList) < len(versionList): reqdList.append(0) if versionList >= reqdList: return True return False def copyDir(srcDir, dstDir): """Copy all regular files from srcDir to dstDir. dstDir is created if necessary. Arguments: srcDir -- the source dir path dstDir -- the destination dir path """ try: if not os.path.isdir(dstDir): os.makedirs(dstDir) names = os.listdir(srcDir) for name in names: srcPath = os.path.join(srcDir, name) if os.path.isfile(srcPath): shutil.copy2(srcPath, os.path.join(dstDir, name)) except (IOError, OSError) as e: if str(e).find('Permission denied') >= 0: print('Error - must be root to install files') cleanSource() sys.exit(4) raise def createWrapper(execDir, execName): """Create a wrapper executable file for a python script in execDir. Arguments: execDir -- the path where the executable is placed execName -- the name for the executable file """ text = '#!/bin/sh\n\nexec {0} {1}/{2}.py "$@"'.format(sys.executable, execDir, execName) with open(execName, 'w') as f: f.write(text) os.chmod(execName, 0o755) def replaceLine(path, origLineStart, newLine): """Replaces lines with origLineStart with newLine and rewrites the file. Arguments: path -- the file to modify origLineStart -- the beginning of the line to be replaced newLine -- the replacement line """ with open(path, 'r') as f: lines = f.readlines() with open(path, 'w') as f: for line in lines: if line.startswith(origLineStart): f.write(newLine) else: f.write(line) def spellCheck(cmdList): """Try spell checkers from list, print result. Arguments: cmdList -- a list of spell checkers to check """ for cmd in cmdList: try: p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.stdout.readline() p.stdin.write(b'!\n') p.stdin.flush() p.stdin.close() p.stdout.close() print(' Spell Checker {0} -> OK'.format(cmd.split()[0])) return except: pass print(' Spell Checker not found -> install aspell, ispell or hunspell') print(' if spell checking is desired') def cleanSource(): """Remove any temporary files added to untarred dirs. """ for name in glob.glob(os.path.join('source', '*.py[co]')): os.remove(name) removeDir(os.path.join('source', '__pycache__')) global progName if os.path.isfile(progName): os.remove(progName) def removeDir(dir): """Remove dir and all files under it, ignore errors. Arguments: dir -- the directory to remove """ try: shutil.rmtree(dir, 1) except: # shouldn't be needed with ignore error param, but pass # some python versions have a bug def main(): """Main installer function. """ optLetters = 'hp:d:t:i:b:sx' try: opts, args = getopt.getopt(sys.argv[1:], optLetters) except getopt.GetoptError: usage(2) global prefixDir global docDir global templateDir global iconToolDir global buildRoot global progName depCheck = True translated = True for opt, val in opts: if opt == '-h': usage(0) elif opt == '-p': prefixDir = os.path.abspath(val) elif opt == '-d': docDir = val elif opt == '-t': templateDir = val elif opt == '-i': iconToolDir = val elif opt == '-b': buildRoot = val elif opt == '-s': translated = False elif opt == '-x': depCheck = False if not os.path.isfile('install.py'): print('Error - {0} files not found'.format(progName)) print('The directory containing "install.py" must be current') sys.exit(4) if (os.path.isdir('source') and not os.path.isfile('source/{0}.py'.format(progName))): print('Error - source files not found') print('Retry the extraction from the tar archive') sys.exit(4) if depCheck: print('Checking dependencies...') pyVersion = sys.version_info[:3] pyVersion = '.'.join([str(num) for num in pyVersion]) if cmpVersions(pyVersion, (3, 9)): print(' Python Version {0} -> OK'.format(pyVersion)) else: print(' Python Version {0} -> Sorry, 3.9 or higher is required' .format(pyVersion)) sys.exit(3) try: from PyQt6 import QtCore, QtWidgets except: print(' PyQt not found -> Sorry, PyQt 6.4 or higher is required' ' and must be built for Python 3') sys.exit(3) qtVersion = QtCore.qVersion() if cmpVersions(qtVersion, (6, 4)): print(' Qt Version {0} -> OK'.format(qtVersion)) else: print(' Qt Version {0} -> Sorry, 6.4 or higher is required' .format(qtVersion)) sys.exit(3) pyqtVersion = QtCore.PYQT_VERSION_STR if cmpVersions(pyqtVersion, (6, 4)): print(' PyQt Version {0} -> OK'.format(pyqtVersion)) else: print(' PyQt Version {0} -> Sorry, 6.4 or higher is required' .format(pyqtVersion)) sys.exit(3) global testSpell if testSpell: spellCheck(['aspell -a', 'ispell -a', 'hunspell -a']) pythonPrefixDir = os.path.join(prefixDir, 'share', progName) pythonBuildDir = os.path.join(buildRoot, pythonPrefixDir[1:]) if os.path.isdir('source'): print('Installing files...') print(' Copying python files to {0}'.format(pythonBuildDir)) removeDir(pythonBuildDir) # remove old? copyDir('source', pythonBuildDir) if os.path.isfile('source/plugininterface.py'): pluginBuildDir = os.path.join(pythonBuildDir, 'plugins') print(' Creating plugins directory if necessary') if not os.path.isdir(pluginBuildDir): os.makedirs(pluginBuildDir) if os.path.isdir('translations') and translated: translationDir = os.path.join(pythonBuildDir, 'translations') print(' Copying translation files to {0}'.format(translationDir)) copyDir('translations', translationDir) if os.path.isdir('doc'): docPrefixDir = docDir.replace('/', '') if not os.path.isabs(docPrefixDir): docPrefixDir = os.path.join(prefixDir, docPrefixDir) docBuildDir = os.path.join(buildRoot, docPrefixDir[1:]) print(' Copying documentation files to {0}'.format(docBuildDir)) copyDir('doc', docBuildDir) if not translated: for name in glob.glob(os.path.join(docBuildDir, '*_[a-z][a-z].')): os.remove(name) # update help file location in main python script replaceLine(os.path.join(pythonBuildDir, '{0}.py'.format(progName)), 'docPath = None', 'docPath = \'{0}\' # modified by install script\n' .format(docPrefixDir)) if os.path.isdir('samples'): sampleBuildDir = os.path.join(docBuildDir, 'samples') print(' Copying sample files to {0}'.format(sampleBuildDir)) copyDir('samples', sampleBuildDir) # update sample file location in main python script replaceLine(os.path.join(pythonBuildDir, '{0}.py'.format(progName)), 'samplePath = None', 'samplePath = \'{0}\' # modified by install script\n' .format(os.path.join(docPrefixDir, 'samples'))) if os.path.isdir('templates'): templatePrefixDir = templateDir.replace('/', '') if not os.path.isabs(templatePrefixDir): templatePrefixDir = os.path.join(prefixDir, templatePrefixDir) templateBuildDir = os.path.join(buildRoot, templatePrefixDir[1:]) print(' Copying template files to {0}'.format(templateBuildDir)) copyDir('templates', templateBuildDir) if not translated: for name in glob.glob(os.path.join(templateBuildDir, '*.trl')): if 'en_' not in os.path.basename(name): os.remove(name) # update template file location in main python script replaceLine(os.path.join(pythonBuildDir, '{0}.py'.format(progName)), 'templatePath = None', 'templatePath = \'{0}\' # modified by install script\n' .format(templatePrefixDir)) if os.path.isdir('templates/exports'): exportsBuildDir = os.path.join(templateBuildDir, 'exports') copyDir('templates/exports', exportsBuildDir) if os.path.isdir('data'): dataPrefixDir = os.path.join(prefixDir, 'share', progName, 'data') dataBuildDir = os.path.join(buildRoot, dataPrefixDir[1:]) print(' Copying data files to {0}'.format(dataBuildDir)) removeDir(dataBuildDir) # remove old? copyDir('data', dataBuildDir) if not translated: for name in glob.glob(os.path.join(dataBuildDir, '*_[a-z][a-z].dat')): os.remove(name) # update data file location in main python script replaceLine(os.path.join(pythonBuildDir, '{0}.py'.format(progName)), 'dataFilePath = None', 'dataFilePath = \'{0}\' # modified by install script\n' .format(dataPrefixDir)) if os.path.isdir('icons'): iconPrefixDir = iconToolDir.replace('/', '') if not os.path.isabs(iconPrefixDir): iconPrefixDir = os.path.join(prefixDir, iconPrefixDir) iconBuildDir = os.path.join(buildRoot, iconPrefixDir[1:]) print(' Copying tool icon files to {0}'.format(iconBuildDir)) copyDir('icons', iconBuildDir) # update icon location in main python script replaceLine(os.path.join(pythonBuildDir, '{0}.py'.format(progName)), 'iconPath = None', 'iconPath = \'{0}\' # modified by install script\n' .format(iconPrefixDir)) if os.path.isdir('icons/toolbar'): iconToolBuildDir = os.path.join(iconBuildDir, 'toolbar') copyDir('icons/toolbar', iconToolBuildDir) if os.path.isdir('icons/toolbar/16x16'): copyDir('icons/toolbar/16x16', os.path.join(iconToolBuildDir, '16x16')) if os.path.isdir('icons/toolbar/32x32'): copyDir('icons/toolbar/32x32', os.path.join(iconToolBuildDir, '32x32')) if os.path.isdir('icons/tree'): copyDir('icons/tree', os.path.join(iconBuildDir, 'tree')) if os.path.isfile(os.path.join('icons', progName + '-icon.png')): pngIconPrefixDir = os.path.join(prefixDir, 'share', 'icons', 'hicolor', '48x48', 'apps') pngIconBuildDir = os.path.join(buildRoot, pngIconPrefixDir[1:]) print(' Copying app icon files to {0}'.format(pngIconBuildDir)) if not os.path.isdir(pngIconBuildDir): os.makedirs(pngIconBuildDir) shutil.copy2(os.path.join('icons', progName + '-icon.png'), pngIconBuildDir) if os.path.isfile(os.path.join('icons', progName + '-icon.svg')): svgIconPrefixDir = os.path.join(prefixDir, 'share', 'icons', 'hicolor', 'scalable', 'apps') svgIconBuildDir = os.path.join(buildRoot, svgIconPrefixDir[1:]) print(' Copying app icon files to {0}'.format(svgIconBuildDir)) if not os.path.isdir(svgIconBuildDir): os.makedirs(svgIconBuildDir) shutil.copy2(os.path.join('icons', progName + '-icon.svg'), svgIconBuildDir) if os.path.isfile(progName + '.desktop'): desktopPrefixDir = os.path.join(prefixDir, 'share', 'applications') desktopBuildDir = os.path.join(buildRoot, desktopPrefixDir[1:]) print(' Copying desktop file to {0}'.format(desktopBuildDir)) if not os.path.isdir(desktopBuildDir): os.makedirs(desktopBuildDir) shutil.copy2(progName + '.desktop', desktopBuildDir) if os.path.isdir('source'): createWrapper(pythonPrefixDir, progName) binBuildDir = os.path.join(buildRoot, prefixDir[1:], 'bin') print(' Copying executable file "{0}" to {1}' .format(progName, binBuildDir)) if not os.path.isdir(binBuildDir): os.makedirs(binBuildDir) shutil.copy2(progName, binBuildDir) compileall.compile_dir(pythonBuildDir, ddir=prefixDir) cleanSource() print('Install complete.') if __name__ == '__main__': main() TreeLine-3.2.1/samples/000077500000000000000000000000001506556630100146775ustar00rootroot00000000000000TreeLine-3.2.1/samples/110en_sample_basic_longtext.trln000066400000000000000000000073221506556630100230560ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "HtmlText", "lines": 12 } ], "formathtml": true, "formatname": "HTML_TEXT", "outputlines": [ "{*Name*}", "{*Text*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "Text", "lines": 12 } ], "formathtml": true, "formatname": "REGULAR_TEXT", "outputlines": [ "{*Name*}", "{*Text*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formatname": "ROOT", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "SpacedText", "lines": 12 } ], "formathtml": true, "formatname": "SPACED_TEXT", "outputlines": [ "{*Name*}{*Text*}" ], "titleline": "{*Name*}" } ], "nodes": [ { "children": [ "ed02751e95a311e79cb17054d2175f18", "ed02771c95a311e79cb17054d2175f18", "ed027aaa95a311e79cb17054d2175f18", "ed027f0095a311e79cb17054d2175f18" ], "data": { "Name": "Text Fields" }, "format": "ROOT", "uid": "ed0270d295a311e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Similar to Treepad", "Text": "This file provides a single long text field for each node. This is similar to how the Treepad program on windows is usually used." }, "format": "REGULAR_TEXT", "uid": "ed02751e95a311e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Regular text field", "Text": "The most commonly used field type is regular text. Formatting such as bold, italics, font sizes and font colors can be used from the Edit menu.
    \n
    \nIt preserves carriage return spaces, but not multiple spaces within a line." }, "format": "REGULAR_TEXT", "uid": "ed02771c95a311e79cb17054d2175f18" }, { "children": [], "data": { "Name": "HTML text field", "Text": "An HTML field allows tags such as italics to be added manually.\n\nIt does not preserve white space.\n\nCharacters like <, >, and & must be escaped." }, "format": "HTML_TEXT", "uid": "ed027aaa95a311e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Spaced text field", "Text": "A spaced text field preserves all white space.\n\nIt does not allow character formatting." }, "format": "SPACED_TEXT", "uid": "ed027f0095a311e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "ed0270d295a311e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/120en_sample_basic_contacts.trln000066400000000000000000000143261506556630100230330ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "FirstName", "fieldtype": "Text" }, { "fieldname": "LastName", "fieldtype": "Text" }, { "fieldname": "Street", "fieldtype": "Text" }, { "fieldname": "City", "fieldtype": "Text" }, { "fieldname": "State", "fieldtype": "Text" }, { "fieldname": "Zip", "fieldtype": "Text" }, { "fieldname": "HomePhone", "fieldtype": "Text" }, { "fieldname": "WorkPhone", "fieldtype": "Text" }, { "fieldname": "MobilePhone", "fieldtype": "Text" }, { "fieldname": "Birthday", "fieldtype": "Date", "format": "%B %-d, %Y" }, { "fieldname": "Email", "fieldtype": "ExternalLink" } ], "formatname": "PERSON", "outputlines": [ "{*FirstName*} {*LastName*}", "{*Street*}", "{*City*}, {*State*} {*Zip*}", "{*HomePhone*} (H)", "{*WorkPhone*} (W)", "{*MobilePhone*} (M)", "DoB: {*Birthday*}", "{*Email*}" ], "titleline": "{*FirstName*} {*LastName*}" }, { "childtype": "TYPE", "fields": [ { "fieldname": "NAME", "fieldtype": "Text" } ], "formatname": "ROOT", "outputlines": [ "{*NAME*}" ], "titleline": "{*NAME*}" }, { "childtype": "PERSON", "fields": [ { "fieldname": "Type", "fieldtype": "Text" } ], "formathtml": true, "formatname": "TYPE", "outputlines": [ "


    {*Type*}" ], "titleline": "{*Type*}" } ], "nodes": [ { "children": [ "fc702b0e95a311e79cb17054d2175f18", "fc703cc095a311e79cb17054d2175f18", "fc70413e95a311e79cb17054d2175f18" ], "data": { "NAME": "Main" }, "format": "ROOT", "uid": "fc7025d295a311e79cb17054d2175f18" }, { "children": [ "fc70345a95a311e79cb17054d2175f18", "fc703af495a311e79cb17054d2175f18" ], "data": { "Type": "Friends" }, "format": "TYPE", "uid": "fc702b0e95a311e79cb17054d2175f18" }, { "children": [], "data": { "Birthday": "2004-11-30", "City": "Nina", "Email": "bill@pinta.com", "FirstName": "Bill", "HomePhone": "(703) 555-5647", "LastName": "Smith", "State": "SC", "Street": "1492 Columbus Drive", "Zip": "35762" }, "format": "PERSON", "uid": "fc70345a95a311e79cb17054d2175f18" }, { "children": [], "data": { "Birthday": "1905-05-08", "City": "Harbor City", "Email": "jj@battleship.org", "FirstName": "John", "HomePhone": "(401) 555-8923", "LastName": "Johnson", "MobilePhone": "(703) 555-2873", "State": "HI", "Street": "1941 Pearl Street", "WorkPhone": "(506) 555-7413", "Zip": "86741" }, "format": "PERSON", "uid": "fc703af495a311e79cb17054d2175f18" }, { "children": [ "fc703e0a95a311e79cb17054d2175f18", "fc703fae95a311e79cb17054d2175f18" ], "data": { "Type": "Family" }, "format": "TYPE", "uid": "fc703cc095a311e79cb17054d2175f18" }, { "children": [], "data": { "Birthday": "1901-07-30", "City": "Dogbone", "Email": "jdoe@spots.net", "FirstName": "Jane", "LastName": "Doe", "MobilePhone": "(654) 555-8527", "State": "SD", "Street": "101 Dalmation Way", "Zip": "52782" }, "format": "PERSON", "uid": "fc703e0a95a311e79cb17054d2175f18" }, { "children": [], "data": { "Birthday": "1999-08-14", "City": "Undersea", "Email": "johndoe@subs.com", "FirstName": "John", "HomePhone": "(805) 555-7296", "LastName": "Doe", "MobilePhone": "(503) 555-8234", "State": "NY", "Street": "20000 Leagues Street", "WorkPhone": "(777) 555-9999", "Zip": "12763" }, "format": "PERSON", "uid": "fc703fae95a311e79cb17054d2175f18" }, { "children": [ "fc70427495a311e79cb17054d2175f18", "fc7043b495a311e79cb17054d2175f18" ], "data": { "Type": "Work" }, "format": "TYPE", "uid": "fc70413e95a311e79cb17054d2175f18" }, { "children": [], "data": { "FirstName": "Dil", "LastName": "Bert", "WorkPhone": "(501) 555-5612" }, "format": "PERSON", "uid": "fc70427495a311e79cb17054d2175f18" }, { "children": [], "data": { "FirstName": "Pointy-haired", "LastName": "Boss", "WorkPhone": "(666) 555-8945" }, "format": "PERSON", "uid": "fc7043b495a311e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "fc7025d295a311e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/130en_sample_basic_booklist.trln000066400000000000000000000123451506556630100230430ustar00rootroot00000000000000{ "formats": [ { "childtype": "BOOK", "fields": [ { "fieldname": "AuthorFirstName", "fieldtype": "Text" }, { "fieldname": "AuthorLastName", "fieldtype": "Text" }, { "fieldname": "WebSite", "fieldtype": "ExternalLink", "prefix": "<", "suffix": ">" } ], "formatname": "AUTHOR", "icon": "book_1", "outputlines": [ "{*AuthorFirstName*} {*AuthorLastName*} {*WebSite*}" ], "titleline": "{*AuthorFirstName*} {*AuthorLastName*}" }, { "fields": [ { "fieldname": "Title", "fieldtype": "Text" }, { "fieldname": "Copyright", "fieldtype": "Number", "format": "0000" }, { "fieldname": "Own", "fieldtype": "Boolean", "format": "yes/no" }, { "fieldname": "ReadDate", "fieldtype": "Date", "format": "%-%-M/%-d/%Y" }, { "fieldname": "Rating", "fieldtype": "Choice", "format": "1/2/3/4/5" }, { "fieldname": "Plot", "fieldtype": "Text", "lines": 7 } ], "formatname": "BOOK", "icon": "book_3", "outputlines": [ "\"{*Title*}\"", "(c) {*Copyright*}, Own: {*Own*}", "Last Read: {*ReadDate*}, Rating: {*Rating*}", "{*Plot*}" ], "titleline": "\"{*Title*}\"" }, { "childtype": "AUTHOR", "fields": [ { "fieldname": "NAME", "fieldtype": "Text" } ], "formatname": "ROOT", "outputlines": [ "{*NAME*}" ], "titleline": "{*NAME*}" } ], "nodes": [ { "children": [ "0bf4f2ee95a411e79cb17054d2175f18", "0bf4ffbe95a411e79cb17054d2175f18" ], "data": { "NAME": "SF Books" }, "format": "ROOT", "uid": "0bf4eeb695a411e79cb17054d2175f18" }, { "children": [ "0bf4f8ca95a411e79cb17054d2175f18", "0bf4fe8895a411e79cb17054d2175f18" ], "data": { "AuthorFirstName": "Greg", "AuthorLastName": "Bear", "WebSite": "www.gregbear.com" }, "format": "AUTHOR", "uid": "0bf4f2ee95a411e79cb17054d2175f18" }, { "children": [], "data": { "Own": "false", "Plot": "Evolution caused by virus begining again", "Rating": "4", "ReadDate": "2000-10-01", "Title": "Darwin's Radio" }, "format": "BOOK", "uid": "0bf4f8ca95a411e79cb17054d2175f18" }, { "children": [], "data": { "Copyright": "1985", "Own": "true", "Plot": "Smart viruses take over", "Rating": "2", "ReadDate": "1998-07-01", "Title": "Blood Music" }, "format": "BOOK", "uid": "0bf4fe8895a411e79cb17054d2175f18" }, { "children": [ "0bf500c295a411e79cb17054d2175f18", "0bf501da95a411e79cb17054d2175f18", "0bf502de95a411e79cb17054d2175f18" ], "data": { "AuthorFirstName": "Orson Scott", "AuthorLastName": "Card", "WebSite": "www.hatrack.com" }, "format": "AUTHOR", "uid": "0bf4ffbe95a411e79cb17054d2175f18" }, { "children": [], "data": { "Copyright": "1996", "Own": "Yes", "Plot": "Time travel to change history; discovery of America", "Rating": "4", "ReadDate": "1998-09-01", "Title": "Pastwatch, The Redemption of Christopher Columbus" }, "format": "BOOK", "uid": "0bf500c295a411e79cb17054d2175f18" }, { "children": [], "data": { "Copyright": "1999", "Own": "Yes", "Plot": "Boy travels back to Russian fairy tale", "Rating": "5", "ReadDate": "2000-08-01", "Title": "Enchantment" }, "format": "BOOK", "uid": "0bf501da95a411e79cb17054d2175f18" }, { "children": [], "data": { "Copyright": "1999", "Own": "Yes", "Plot": "Ender's Game from Bean's perspective", "Rating": "5", "ReadDate": "2001-05-01", "Title": "Ender's Shadow" }, "format": "BOOK", "uid": "0bf502de95a411e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "0bf4eeb695a411e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/140en_sample_genealogy.trln000066400000000000000000000162061506556630100220270ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Birth", "fieldtype": "Date", "format": "%B %-d, %Y" }, { "fieldname": "Death", "fieldtype": "Date", "format": "%B %-d, %Y" }, { "fieldname": "Location", "fieldtype": "Text" } ], "formatname": "MEMBER", "outputlines": [ "{*Name*}", "Born: {*Birth*}", "Died: {*Death*}", "Where: {*Location*}" ], "titleline": "{*Name*}" } ], "nodes": [ { "children": [ "5086f03aaf3a11e7a6243417ebd53aeb", "959dd4e8af3a11e7a4263417ebd53aeb", "a19ee912af3a11e79a1a3417ebd53aeb", "a3ed3f0aaf3a11e799293417ebd53aeb" ], "data": { "Birth": "1935-05-04", "Location": "St. Louis, MO", "Name": "Grandma Jones" }, "format": "MEMBER", "uid": "0ec2773aaf3a11e79eea3417ebd53aeb" }, { "children": [ "4b6295b4af3a11e7beaa3417ebd53aeb", "7c6a86deaf3a11e795c23417ebd53aeb", "8630c54caf3a11e7b24c3417ebd53aeb" ], "data": { "Birth": "1935-07-30", "Location": "Las Vegas, NV", "Name": "Grandpa Smith" }, "format": "MEMBER", "uid": "1b0fdaefaf3911e785d43417ebd53aeb" }, { "children": [], "data": { "Birth": "1992-07-15", "Location": "Denver, CO", "Name": "Linda" }, "format": "MEMBER", "uid": "3096a564af3b11e7b9a63417ebd53aeb" }, { "children": [], "data": { "Birth": "1995-02-14", "Location": "Boston, MA", "Name": "Billy" }, "format": "MEMBER", "uid": "35eb10b6af3b11e7b0593417ebd53aeb" }, { "children": [ "f571c05eaf3a11e793b33417ebd53aeb", "3096a564af3b11e7b9a63417ebd53aeb", "35eb10b6af3b11e7b0593417ebd53aeb" ], "data": { "Birth": "1960-08-16", "Location": "Dallas, TX", "Name": "Papa" }, "format": "MEMBER", "uid": "4b6295b4af3a11e7beaa3417ebd53aeb" }, { "children": [ "f571c05eaf3a11e793b33417ebd53aeb", "3096a564af3b11e7b9a63417ebd53aeb", "35eb10b6af3b11e7b0593417ebd53aeb" ], "data": { "Birth": "1962-02-10", "Location": "Dallas, TX", "Name": "Mama" }, "format": "MEMBER", "uid": "5086f03aaf3a11e7a6243417ebd53aeb" }, { "children": [], "data": { "Birth": "1985-12-25", "Location": "Phoenix, AZ", "Name": "Cousin Jimmy" }, "format": "MEMBER", "uid": "7baaa7baaf3b11e7bf9a3417ebd53aeb" }, { "children": [], "data": { "Birth": "2062-06-23", "Location": "Pittsburgh, PA", "Name": "Uncle Mike" }, "format": "MEMBER", "uid": "7c6a86deaf3a11e795c23417ebd53aeb" }, { "children": [], "data": { "Birth": "1987-08-31", "Location": "Houston, TX", "Name": "Cousin Dave" }, "format": "MEMBER", "uid": "81d4264aaf3b11e7b17f3417ebd53aeb" }, { "children": [ "7baaa7baaf3b11e7bf9a3417ebd53aeb", "81d4264aaf3b11e7b17f3417ebd53aeb" ], "data": { "Birth": "2065-12-08", "Location": "Cleveland, OH", "Name": "Aunt Mary" }, "format": "MEMBER", "uid": "8630c54caf3a11e7b24c3417ebd53aeb" }, { "children": [], "data": { "Birth": "1984-10-05", "Location": "New York, NY", "Name": "Cousin Joe" }, "format": "MEMBER", "uid": "916e641eaf3b11e78c293417ebd53aeb" }, { "children": [], "data": { "Birth": "2064-06-05", "Location": "Los Angelos, CA", "Name": "Aunt Patty" }, "format": "MEMBER", "uid": "959dd4e8af3a11e7a4263417ebd53aeb" }, { "children": [], "data": { "Birth": "1990-07-20", "Location": "Bar Harbor, ME", "Name": "Cousin Susan" }, "format": "MEMBER", "uid": "9bba64f8af3b11e78b123417ebd53aeb" }, { "children": [ "916e641eaf3b11e78c293417ebd53aeb", "9bba64f8af3b11e78b123417ebd53aeb" ], "data": { "Birth": "2067-11-10", "Location": "Philadelphia, PA", "Name": "Aunt Jenny" }, "format": "MEMBER", "uid": "a19ee912af3a11e79a1a3417ebd53aeb" }, { "children": [ "a4371f0caf3b11e7ac8b3417ebd53aeb" ], "data": { "Birth": "1969-05-31", "Location": "Baltimore, MD", "Name": "Uncle Bobby" }, "format": "MEMBER", "uid": "a3ed3f0aaf3a11e799293417ebd53aeb" }, { "children": [], "data": { "Birth": "1980-06-25", "Location": "Wilmington, NC", "Name": "Cousin Steve" }, "format": "MEMBER", "uid": "a4371f0caf3b11e7ac8b3417ebd53aeb" }, { "children": [ "4b6295b4af3a11e7beaa3417ebd53aeb", "7c6a86deaf3a11e795c23417ebd53aeb", "8630c54caf3a11e7b24c3417ebd53aeb" ], "data": { "Birth": "1937-04-12", "Location": "Las Vegas, NV", "Name": "Grandma Smith" }, "format": "MEMBER", "uid": "d3b3f1c8af3911e79f6f3417ebd53aeb" }, { "children": [ "5086f03aaf3a11e7a6243417ebd53aeb", "959dd4e8af3a11e7a4263417ebd53aeb", "a19ee912af3a11e79a1a3417ebd53aeb", "a3ed3f0aaf3a11e799293417ebd53aeb" ], "data": { "Birth": "1932-09-17", "Location": "St. Louis, MO", "Name": "Grandpa Jones" }, "format": "MEMBER", "uid": "f0f4f1f4af3911e790383417ebd53aeb" }, { "children": [], "data": { "Birth": "1989-05-31", "Location": "San Francisco, CA", "Name": "Me" }, "format": "MEMBER", "uid": "f571c05eaf3a11e793b33417ebd53aeb" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "1b0fdaefaf3911e785d43417ebd53aeb", "d3b3f1c8af3911e79f6f3417ebd53aeb", "f0f4f1f4af3911e790383417ebd53aeb", "0ec2773aaf3a11e79eea3417ebd53aeb" ] } }TreeLine-3.2.1/samples/210en_sample_char_format.trln000066400000000000000000000057401506556630100223410ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formatname": "ROOT", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "TOPIC", "fieldtype": "Text" }, { "fieldname": "TEXT", "fieldtype": "Text", "lines": 7 } ], "formathtml": true, "formatname": "TEXT_PARA", "icon": "doc", "outputlines": [ "{*TOPIC*}", "{*TEXT*}" ], "titleline": "{*TOPIC*}" } ], "nodes": [ { "children": [ "14e55e4895a411e79cb17054d2175f18", "14e5604695a411e79cb17054d2175f18", "14e5616895a411e79cb17054d2175f18", "14e5626c95a411e79cb17054d2175f18", "14e5635c95a411e79cb17054d2175f18" ], "data": { "Name": "Character Format Examples" }, "format": "ROOT", "uid": "14e559fc95a411e79cb17054d2175f18" }, { "children": [], "data": { "TEXT": "All titles can be set to bold by adding <b>...</b> tags in the Configure Data Types dialog's Output tab. The \"Allow HTML rich text in format\" option must also be checked in the Type Config tab.", "TOPIC": "Bold Titles" }, "format": "TEXT_PARA", "uid": "14e55e4895a411e79cb17054d2175f18" }, { "children": [], "data": { "TEXT": "Font formatting commands can be found in the Edit menu and in the right-click context menu in the \"Data Editor\" view.", "TOPIC": "Bold Text" }, "format": "TEXT_PARA", "uid": "14e5604695a411e79cb17054d2175f18" }, { "children": [], "data": { "TEXT": "Text can also be set to various colors.", "TOPIC": "Colored Text" }, "format": "TEXT_PARA", "uid": "14e5616895a411e79cb17054d2175f18" }, { "children": [], "data": { "TEXT": "Large text and small text", "TOPIC": "Font Size" }, "format": "TEXT_PARA", "uid": "14e5626c95a411e79cb17054d2175f18" }, { "children": [], "data": { "TEXT": "Text in italics and even text underlined", "TOPIC": "Italics and Underline" }, "format": "TEXT_PARA", "uid": "14e5635c95a411e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "14e559fc95a411e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/220en_sample_bookmarks.trln000066400000000000000000000304471506556630100220470ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Link", "fieldtype": "ExternalLink" } ], "formatname": "BOOKMARK", "icon": "bookmark", "outputlines": [ "{*Name*}", "{*Link*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formatname": "FOLDER", "icon": "folder_3", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "SEPARATOR", "outputlines": [ "
    " ], "titleline": "------------------" } ], "nodes": [ { "children": [ "25608cd495a411e79cb17054d2175f18", "25609bde95a411e79cb17054d2175f18", "2560aca095a411e79cb17054d2175f18", "2560b66495a411e79cb17054d2175f18" ], "data": { "Name": "Bookmarks Menu" }, "format": "FOLDER", "uid": "25608acc95a411e79cb17054d2175f18" }, { "children": [ "25608df695a411e79cb17054d2175f18", "2560970695a411e79cb17054d2175f18" ], "data": { "Name": "Information" }, "format": "FOLDER", "uid": "25608cd495a411e79cb17054d2175f18" }, { "children": [ "256091c095a411e79cb17054d2175f18", "256093e695a411e79cb17054d2175f18", "256094f495a411e79cb17054d2175f18", "2560960295a411e79cb17054d2175f18" ], "data": { "Name": "News" }, "format": "FOLDER", "uid": "25608df695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.abcnews.com/", "Name": "ABC News" }, "format": "BOOKMARK", "uid": "256091c095a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.cnn.com/", "Name": "CNN.com" }, "format": "BOOKMARK", "uid": "256093e695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.usatoday.com/", "Name": "USA Today" }, "format": "BOOKMARK", "uid": "256094f495a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://washingtonpost.com/", "Name": "WashingtonPost" }, "format": "BOOKMARK", "uid": "2560960295a411e79cb17054d2175f18" }, { "children": [ "256097f695a411e79cb17054d2175f18", "256098f095a411e79cb17054d2175f18", "256099e095a411e79cb17054d2175f18", "25609ad095a411e79cb17054d2175f18" ], "data": { "Name": "Reference" }, "format": "FOLDER", "uid": "2560970695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://dictionary.com/", "Name": "Dictionary.com" }, "format": "BOOKMARK", "uid": "256097f695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.dict.org/", "Name": "DICT" }, "format": "BOOKMARK", "uid": "256098f095a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://ibiblio.org/", "Name": "ibiblio" }, "format": "BOOKMARK", "uid": "256099e095a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://en.wikipedia.org/wiki/Main_Page", "Name": "Wikipedia" }, "format": "BOOKMARK", "uid": "25609ad095a411e79cb17054d2175f18" }, { "children": [ "25609cba95a411e79cb17054d2175f18", "2560a8cc95a411e79cb17054d2175f18" ], "data": { "Name": "Linux" }, "format": "FOLDER", "uid": "25609bde95a411e79cb17054d2175f18" }, { "children": [ "2560a4c695a411e79cb17054d2175f18", "2560a5de95a411e79cb17054d2175f18", "2560a6ce95a411e79cb17054d2175f18", "2560a7dc95a411e79cb17054d2175f18" ], "data": { "Name": "Debian" }, "format": "FOLDER", "uid": "25609cba95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.debian.org/", "Name": "debian.org" }, "format": "BOOKMARK", "uid": "2560a4c695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://packages.debian.org/unstable/", "Name": "Packages in \"unstable\"" }, "format": "BOOKMARK", "uid": "2560a5de95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://packages.debian.org/experimental/", "Name": "Packages in \"experimental\"" }, "format": "BOOKMARK", "uid": "2560a6ce95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://planet.debian.net/", "Name": "Planet Debian" }, "format": "BOOKMARK", "uid": "2560a7dc95a411e79cb17054d2175f18" }, { "children": [ "2560a9bc95a411e79cb17054d2175f18", "2560aaac95a411e79cb17054d2175f18", "2560ab9295a411e79cb17054d2175f18" ], "data": { "Name": "News" }, "format": "FOLDER", "uid": "2560a8cc95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://linuxtoday.com/", "Name": "Linux Today" }, "format": "BOOKMARK", "uid": "2560a9bc95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.lwn.net/", "Name": "Linux Weekly News" }, "format": "BOOKMARK", "uid": "2560aaac95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.h-online.com/", "Name": "The H" }, "format": "BOOKMARK", "uid": "2560ab9295a411e79cb17054d2175f18" }, { "children": [ "2560ad7c95a411e79cb17054d2175f18", "2560b11495a411e79cb17054d2175f18", "2560b3bc95a411e79cb17054d2175f18" ], "data": { "Name": "Programming" }, "format": "FOLDER", "uid": "2560aca095a411e79cb17054d2175f18" }, { "children": [ "2560ae5895a411e79cb17054d2175f18", "2560af3e95a411e79cb17054d2175f18", "2560b02495a411e79cb17054d2175f18" ], "data": { "Name": "PyQt" }, "format": "FOLDER", "uid": "2560ad7c95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.diotavelli.net/PyQtWiki", "Name": "PyQt Wiki" }, "format": "BOOKMARK", "uid": "2560ae5895a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.riverbankcomputing.co.uk/", "Name": "Riverbank PyQt" }, "format": "BOOKMARK", "uid": "2560af3e95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://qt.nokia.com/", "Name": "QT Trolltech" }, "format": "BOOKMARK", "uid": "2560b02495a411e79cb17054d2175f18" }, { "children": [ "2560b1e695a411e79cb17054d2175f18", "2560b2cc95a411e79cb17054d2175f18" ], "data": { "Name": "Python" }, "format": "FOLDER", "uid": "2560b11495a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.oreillynet.com/python/", "Name": "OReilly Python" }, "format": "BOOKMARK", "uid": "2560b1e695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.python.org/", "Name": "Python" }, "format": "BOOKMARK", "uid": "2560b2cc95a411e79cb17054d2175f18" }, { "children": [ "2560b48e95a411e79cb17054d2175f18", "2560b57495a411e79cb17054d2175f18" ], "data": { "Name": "Tools" }, "format": "FOLDER", "uid": "2560b3bc95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.selenic.com/mercurial/wiki/", "Name": "Mercurial" }, "format": "BOOKMARK", "uid": "2560b48e95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://hgbook.red-bean.com/hgbook.html", "Name": "Mercurial Book" }, "format": "BOOKMARK", "uid": "2560b57495a411e79cb17054d2175f18" }, { "children": [ "2560b73695a411e79cb17054d2175f18", "2560b82695a411e79cb17054d2175f18", "2560b92a95a411e79cb17054d2175f18" ], "data": { "Name": "Weather" }, "format": "FOLDER", "uid": "2560b66495a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.aviationweather.gov/adds", "Name": "ADDS - Aviation Digital Data Service" }, "format": "BOOKMARK", "uid": "2560b73695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://forecast.weather.gov/MapClick.php?lat=39.105&lon=-77.26", "Name": "NOAA" }, "format": "BOOKMARK", "uid": "2560b82695a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "http://www.wunderground.com/cgi-bin/findweather/getForecast?query=gai", "Name": "Weather Underground" }, "format": "BOOKMARK", "uid": "2560b92a95a411e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "25608acc95a411e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/230en_sample_intern_links.trln000066400000000000000000000047001506556630100225500ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "Text" } ], "formatname": "DEFAULT", "outputlines": [ "{*Name*}", "{*Text*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Link", "fieldtype": "InternalLink" } ], "formatname": "LINK_TYPE", "outputlines": [ "{*Name*}", "{*Link*}" ], "titleline": "{*Name*}" } ], "nodes": [ { "children": [ "2d70acb095a411e79cb17054d2175f18", "2d70aec295a411e79cb17054d2175f18", "2d70afd095a411e79cb17054d2175f18" ], "data": { "Name": "Main" }, "format": "DEFAULT", "uid": "2d70a88c95a411e79cb17054d2175f18" }, { "children": [], "data": { "Link": "Target Node", "Name": "Using the external link field" }, "format": "LINK_TYPE", "uid": "2d70acb095a411e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Embedded links", "Text": "Links can be embedded in any text field text by using the Internal Link item from the Edit Menu. The \"Enable click on target\" button lets you simply click on the target node." }, "format": "DEFAULT", "uid": "2d70aec295a411e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Target Node", "Text": "By default, the target node gets its unique ID from the content of its first field. This can be changed in the Type Config tab of the Configure Types dialog. Use the Show Advanced button to show the control for the Unique ID Reference." }, "format": "DEFAULT", "uid": "2d70afd095a411e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "2d70a88c95a411e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/240en_sample_table_booklist.trln000066400000000000000000000066011506556630100230510ustar00rootroot00000000000000{ "formats": [ { "childtype": "BOOK", "fields": [ { "fieldname": "AuthorFirstName", "fieldtype": "Text" }, { "fieldname": "AuthorLastName", "fieldtype": "Text" }, { "fieldname": "WebSite", "fieldtype": "ExternalLink", "prefix": "<", "suffix": ">" } ], "formatname": "AUTHOR", "icon": "book_1", "outputlines": [ "{*AuthorFirstName*} {*AuthorLastName*} {*WebSite*}" ], "titleline": "{*AuthorFirstName*} {*AuthorLastName*}" }, { "fields": [ { "fieldname": "Title", "fieldtype": "Text" }, { "fieldname": "Copyright", "fieldtype": "Number", "format": "0000" }, { "fieldname": "Own", "fieldtype": "Boolean", "format": "yes/no" }, { "fieldname": "ReadDate", "fieldtype": "Date", "format": "%-m/%-d/%Y" }, { "fieldname": "Rating", "fieldtype": "Choice", "format": "1/2/3/4/5" }, { "fieldname": "Plot", "fieldtype": "Text", "lines": 7 } ], "formathtml": true, "formatname": "BOOK", "icon": "book_3", "outputlines": [ "Title: \"{*Title*}\"", "Status: (c) {*Copyright*}", "Own: {*Own*}", "Last Read: {*ReadDate*}", "Rating: {*Rating*}", "Plot: {*Plot*}" ], "spacebetween": false, "tables": true, "titleline": "\"{*Title*}\"" }, { "childtype": "AUTHOR", "fields": [ { "fieldname": "NAME", "fieldtype": "Text" } ], "formatname": "ROOT", "outputlines": [ "{*NAME*}" ], "titleline": "{*NAME*}" } ], "nodes": [ { "children": [ "5cd2946cfe1011e7b8dc7054d2175f18", "5cd2bffafe1011e7b8dc7054d2175f18" ], "data": { "NAME": "SF Books" }, "format": "ROOT", "uid": "5cd28d1efe1011e7b8dc7054d2175f18" }, { "children": [ "5cd2b3d4fe1011e7b8dc7054d2175f18", "5cd2bdc0fe1011e7b8dc7054d2175f18" ], "data": { "AuthorFirstName": "Greg", "AuthorLastName": "Bear", "WebSite": "www.gregbear.com" }, "format": "AUTHOR", "uid": "5cd2946cfe1011e7b8dc7054d2175f18" }, { "children": [], "data": { "Copyright": "1999", "Own": "false", "Plot": "Evolution caused by virus begining again", "Rating": "4", "ReadDate": "2000-10-01", "Title": "Darwin's Radio" }, "format": "BOOK", "uid": "5cd2b3d4fe1011e7b8dc7054d2175f18" }, { "children": [], "data": { "Copyright": "1985", "Own": "true", "Plot": "Smart viruses take over", "Rating": "2", "ReadDate": "1998-07-01", "Title": "Blood Music" }, "format": "BOOK", "uid": "5cd2bdc0fe1011e7b8dc7054d2175f18" }, { "children": [ "5cd2c1bcfe1011e7b8dc7054d2175f18", "5cd2c392fe1011e7b8dc7054d2175f18", "5cd2c54afe1011e7b8dc7054d2175f18" ], "data": { "AuthorFirstName": "Orson Scott", "AuthorLastName": "Card", "WebSite": "www.hatrack.com" }, "format": "AUTHOR", "uid": "5cd2bffafe1011e7b8dc7054d2175f18" }, { "children": [], "data": { "Copyright": "1996", "Own": "Yes", "Plot": "Time travel to change history; discovery of America", "Rating": "4", "ReadDate": "1998-09-01", "Title": "Pastwatch, The Redemption of Christopher Columbus" }, "format": "BOOK", "uid": "5cd2c1bcfe1011e7b8dc7054d2175f18" }, { "children": [], "data": { "Copyright": "1999", "Own": "Yes", "Plot": "Boy travels back to Russian fairy tale", "Rating": "5", "ReadDate": "2000-08-01", "Title": "Enchantment" }, "format": "BOOK", "uid": "5cd2c392fe1011e7b8dc7054d2175f18" }, { "children": [], "data": { "Copyright": "1999", "Own": "Yes", "Plot": "Ender's Game from Bean's perspective", "Rating": "5", "ReadDate": "2001-05-01", "Title": "Ender's Shadow" }, "format": "BOOK", "uid": "5cd2c54afe1011e7b8dc7054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "5cd28d1efe1011e7b8dc7054d2175f18" ] } }TreeLine-3.2.1/samples/310en_sample_conditional_todo.trln000066400000000000000000000137511506556630100234060ustar00rootroot00000000000000{ "formats": [ { "childtype": "TASK_UNDONE", "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "ROOT", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "condition": "Done == \"true\"", "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Done", "fieldtype": "Boolean", "format": "yes/no", "init": "false" }, { "fieldname": "Urgent", "fieldtype": "Boolean", "format": "yes/no", "init": "false" } ], "formathtml": true, "formatname": "TASK_DONE", "icon": "smiley_4", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Done", "fieldtype": "Boolean", "format": "yes/no", "init": "false" }, { "fieldname": "Urgent", "fieldtype": "Boolean", "format": "yes/no", "init": "false" } ], "formathtml": true, "formatname": "TASK_UNDONE", "generic": "TASK_DONE", "icon": "smiley_2", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "condition": "Done == \"false\" and Urgent == \"true\"", "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Done", "fieldtype": "Boolean", "format": "yes/no", "init": "false" }, { "fieldname": "Urgent", "fieldtype": "Boolean", "format": "yes/no", "init": "true" } ], "formathtml": true, "formatname": "TASK_UNDONE_URGENT", "generic": "TASK_DONE", "icon": "smiley_5", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}!!!" } ], "nodes": [ { "children": [ "4295fc4e95a411e79cb17054d2175f18", "42960f7c95a411e79cb17054d2175f18" ], "data": { "Name": "Conditional Task List" }, "format": "ROOT", "uid": "4295faaa95a411e79cb17054d2175f18" }, { "children": [ "4295ff6e95a411e79cb17054d2175f18", "429602ac95a411e79cb17054d2175f18", "429603c495a411e79cb17054d2175f18", "429607b695a411e79cb17054d2175f18", "42960cca95a411e79cb17054d2175f18" ], "data": { "Name": "Home Tasks" }, "format": "ROOT", "uid": "4295fc4e95a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Mow lawn", "Urgent": "false" }, "format": "TASK_UNDONE", "uid": "4295ff6e95a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Patch wall", "Urgent": "false" }, "format": "TASK_UNDONE", "uid": "429602ac95a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Vacuum", "Urgent": "false" }, "format": "TASK_UNDONE", "uid": "429603c495a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Walk dog", "Urgent": "true" }, "format": "TASK_UNDONE_URGENT", "uid": "429607b695a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "true", "Name": "Watch TV", "Urgent": "false" }, "format": "TASK_DONE", "uid": "42960cca95a411e79cb17054d2175f18" }, { "children": [ "4296107695a411e79cb17054d2175f18", "429611b695a411e79cb17054d2175f18", "429612a695a411e79cb17054d2175f18", "4296139695a411e79cb17054d2175f18" ], "data": { "Name": "Work Tasks" }, "format": "ROOT", "uid": "42960f7c95a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "true", "Name": "Play solitaire", "Urgent": "false" }, "format": "TASK_DONE", "uid": "4296107695a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Write documents", "Urgent": "false" }, "format": "TASK_UNDONE", "uid": "429611b695a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "true", "Name": "Eat lunch", "Urgent": "false" }, "format": "TASK_DONE", "uid": "429612a695a411e79cb17054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Compliment boss", "Urgent": "true" }, "format": "TASK_UNDONE_URGENT", "uid": "4296139695a411e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "4295faaa95a411e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/320en_sample_other_fields.trln000066400000000000000000000106641506556630100225260ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "DEFAULT", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "childtype": "DEFAULT", "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "FILE_INFO", "outputlines": [ "{*Name*}", "File: {*!File_Path*}/{*!File_Name*}", "File Size: {*!File_Size*} bytes", "File Modified: {*!File_Mod_Date*} {*!File_Mod_Time*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "File_Name", "fieldtype": "Text" }, { "fieldname": "File_Path", "fieldtype": "Text" }, { "fieldname": "File_Size", "fieldtype": "Number", "format": "#" }, { "fieldname": "File_Mod_Date", "fieldtype": "Date", "format": "%B %-d, %Y" }, { "fieldname": "File_Mod_Time", "fieldtype": "Time", "format": "%-I:%M:%S %p" }, { "fieldname": "File_Owner", "fieldtype": "Text" }, { "fieldname": "Page_Number", "fieldtype": "Text" }, { "fieldname": "Number_of_Pages", "fieldtype": "Text" } ], "formatname": "INT_TL_FILE_DATA_FORM", "outputlines": [ "" ], "titleline": "" }, { "childtype": "DEFAULT", "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "PARENT_CHILD", "outputlines": [ "{*Name*}", "Parent's Name: {**Name*}", "Children's Names: {*&Name*}" ], "titleline": "{*Name*}" }, { "childtype": "DEFAULT", "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "ROOT", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" } ], "nodes": [ { "children": [ "50cdc8dc95a411e79cb17054d2175f18", "50cdce0495a411e79cb17054d2175f18", "50cdcf7695a411e79cb17054d2175f18" ], "data": { "Name": "Other Field References" }, "format": "ROOT", "uid": "50cdc36e95a411e79cb17054d2175f18" }, { "children": [], "data": { "Name": "File Information" }, "format": "FILE_INFO", "uid": "50cdc8dc95a411e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Parent Info" }, "format": "PARENT_CHILD", "uid": "50cdce0495a411e79cb17054d2175f18" }, { "children": [ "50cdd27895a411e79cb17054d2175f18", "50cdd3e095a411e79cb17054d2175f18", "50cdd4e495a411e79cb17054d2175f18" ], "data": { "Name": "Child Info" }, "format": "PARENT_CHILD", "uid": "50cdcf7695a411e79cb17054d2175f18" }, { "children": [], "data": { "Name": "First child" }, "format": "DEFAULT", "uid": "50cdd27895a411e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Next child" }, "format": "DEFAULT", "uid": "50cdd3e095a411e79cb17054d2175f18" }, { "children": [], "data": { "Name": "Third child" }, "format": "DEFAULT", "uid": "50cdd4e495a411e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "50cdc36e95a411e79cb17054d2175f18" ] } }TreeLine-3.2.1/samples/330en_sample_math_fields.trln000066400000000000000000000156401506556630100223360ustar00rootroot00000000000000{ "formats": [ { "childtype": "PART", "fields": [ { "fieldname": "PartNumber", "fieldtype": "Text" }, { "fieldname": "Name", "fieldtype": "Text" }, { "eqn": "{**Level*} + 1", "fieldname": "Level", "fieldtype": "Math", "format": "#" }, { "fieldname": "LaborCost", "fieldtype": "Number", "format": "0.00", "prefix": "$" }, { "eqn": "sum({*&Cost*}) + {*LaborCost*}", "fieldname": "Cost", "fieldtype": "Math", "format": "0.00", "prefix": "$" }, { "eqn": "{**TotalCost*}", "fieldname": "TotalCost", "fieldtype": "Math", "format": "0.00", "prefix": "$" }, { "eqn": "{*Cost*} / {*TotalCost*} * 100", "fieldname": "PercentCost", "fieldtype": "Math", "format": "0", "suffix": "%" } ], "formatname": "ASSEMBLY", "outputlines": [ "Part {*PartNumber*}", "{*Name*}", "Assembly Level: {*Level*}", "Cost: {*Cost*}", "Percent Cost: {*PercentCost*}" ], "titleline": "{*PartNumber*} {*Name*}" }, { "fields": [ { "fieldname": "PartNumber", "fieldtype": "Text" }, { "fieldname": "Name", "fieldtype": "Text" }, { "eqn": "{**Level*} + 1", "fieldname": "Level", "fieldtype": "Math", "format": "#" }, { "fieldname": "Cost", "fieldtype": "Number", "format": "0.00", "prefix": "$" }, { "eqn": "{*Cost*} / {**TotalCost*} * 100", "fieldname": "PercentCost", "fieldtype": "Math", "format": "0", "suffix": "%" }, { "eqn": "('Low') if ({*PercentCost*} < 20) else ('High')", "fieldname": "CostLevel", "fieldtype": "Math", "format": "#.##", "resulttype": "text" } ], "formatname": "PART", "outputlines": [ "Part {*PartNumber*}", "{*Name*}", "Assembly Level: {*Level*}", "Cost: {*Cost*}", "Percent Cost: {*PercentCost*}", "Cost Level: {*CostLevel*}" ], "titleline": "{*PartNumber*} {*Name*}" }, { "childtype": "ASSEMBLY", "fields": [ { "fieldname": "PartNumber", "fieldtype": "Text" }, { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Level", "fieldtype": "Number", "format": "#" }, { "fieldname": "LaborCost", "fieldtype": "Number", "format": "0.00", "prefix": "$" }, { "eqn": "sum({*&Cost*}) + {*LaborCost*}", "fieldname": "TotalCost", "fieldtype": "Math", "format": "0.00", "prefix": "$" } ], "formatname": "TOP_ASSEMBLY", "outputlines": [ "Part {*PartNumber*}", "{*Name*}", "Assembly Level: {*Level*}", "Cost: {*TotalCost*}" ], "titleline": "{*PartNumber*} {*Name*}" } ], "nodes": [ { "children": [ "5f8ff84a95a411e79cb17054d2175f18", "5f901e5695a411e79cb17054d2175f18" ], "data": { "LaborCost": "3.5", "Level": "1", "Name": "Widget Top Assembly", "PartNumber": "123456", "TotalCost": "23.89" }, "format": "TOP_ASSEMBLY", "uid": "5f8fdd3895a411e79cb17054d2175f18" }, { "children": [ "5f900eb695a411e79cb17054d2175f18", "5f901d0c95a411e79cb17054d2175f18" ], "data": { "Cost": "10.040000000000001", "LaborCost": "1.75", "Level": "2", "Name": "Lever Assembly", "PartNumber": "456789", "PercentCost": "42.02595228128925", "TotalCost": "23.89" }, "format": "ASSEMBLY", "uid": "5f8ff84a95a411e79cb17054d2175f18" }, { "children": [], "data": { "Cost": "5.4", "CostLevel": "High", "Level": "3", "Name": "Lever", "PartNumber": "987654", "PercentCost": "22.60359983256593" }, "format": "PART", "uid": "5f900eb695a411e79cb17054d2175f18" }, { "children": [], "data": { "Cost": "2.89", "CostLevel": "Low", "Level": "3", "Name": "Lever Bolt", "PartNumber": "998877", "PercentCost": "12.097111762243616" }, "format": "PART", "uid": "5f901d0c95a411e79cb17054d2175f18" }, { "children": [ "5f901f6e95a411e79cb17054d2175f18", "5f90208695a411e79cb17054d2175f18" ], "data": { "Cost": "10.35", "LaborCost": "2.25", "Level": "2", "Name": "Bracket Assembly", "PartNumber": "112233", "PercentCost": "43.32356634575136", "TotalCost": "23.89" }, "format": "ASSEMBLY", "uid": "5f901e5695a411e79cb17054d2175f18" }, { "children": [], "data": { "Cost": "6.2", "CostLevel": "High", "Level": "3", "Name": "Bracket", "PartNumber": "445566", "PercentCost": "25.952281289242364" }, "format": "PART", "uid": "5f901f6e95a411e79cb17054d2175f18" }, { "children": [], "data": { "Cost": "1.9", "CostLevel": "Low", "Level": "3", "Name": "Bracket Pin", "PartNumber": "665544", "PercentCost": "7.95311845960653" }, "format": "PART", "uid": "5f90208695a411e79cb17054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "5f8fdd3895a411e79cb17054d2175f18" ] } }TreeLine-3.2.1/source/000077500000000000000000000000001506556630100145335ustar00rootroot00000000000000TreeLine-3.2.1/source/breadcrumbview.py000066400000000000000000000162771506556630100201230ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # breadcrumbview.py, provides a class for the breadcrumb view # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import operator from PyQt6.QtCore import QSize, Qt from PyQt6.QtGui import QPainter, QPalette from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QStyledItemDelegate, QTableWidget, QTableWidgetItem) import globalref class CrumbItem(QTableWidgetItem): """Class to store breadcrumb item spot refs and positions. """ def __init__(self, spotRef): """Initialize the breadcrumb item. Arguments: spotRef -- ref to the associated spot item """ super().__init__(spotRef.nodeRef.title(spotRef)) self.spot = spotRef self.selectedSpot = False self.setTextAlignment(Qt.AlignmentFlag.AlignCenter) self.setForeground(QApplication.palette().brush(QPalette. ColorRole.Link)) class BorderDelegate(QStyledItemDelegate): """Class override to show borders between rows. """ def __init__(self, parent=None): """Initialize the delegate class. Arguments: parent -- the parent view """ super().__init__(parent) def paint(self, painter, styleOption, modelIndex): """Paint the cells with borders between rows. """ super().paint(painter, styleOption, modelIndex) cell = self.parent().item(modelIndex.row(), modelIndex.column()) if modelIndex.row() > 0 and cell: upperCell = None row = modelIndex.row() while not upperCell and row > 0: row -= 1 upperCell = self.parent().item(row, modelIndex.column()) if cell.text() and upperCell and upperCell.text(): painter.drawLine(styleOption.rect.topLeft(), styleOption.rect.topRight()) class BreadcrumbView(QTableWidget): """Class override for the breadcrumb view. Sets view defaults and updates the content. """ def __init__(self, treeView, parent=None): """Initialize the breadcrumb view. Arguments: treeView - the tree view, needed for the current selection model parent -- the parent main window """ super().__init__(parent) self.treeView = treeView self.borderItems = [] self.setFocusPolicy(Qt.FocusPolicy.NoFocus) self.horizontalHeader().hide() self.verticalHeader().hide() self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel) self.setHorizontalScrollMode(QAbstractItemView.ScrollMode. ScrollPerPixel) self.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.setItemDelegate(BorderDelegate(self)) self.setShowGrid(False) self.setMouseTracking(True) self.itemClicked.connect(self.changeSelection) def updateContents(self): """Reload the view's content if the view is shown. Avoids update if view is not visible or has zero height or width. """ if not self.isVisible() or self.height() == 0 or self.width() == 0: return self.clear() self.clearSpans() selModel = self.treeView.selectionModel() selSpots = selModel.selectedSpots() if len(selSpots) != 1: return selSpot = selSpots[0] spotList = sorted(list(selSpot.nodeRef.spotRefs), key=operator.methodcaller('sortKey')) chainList = [[CrumbItem(chainSpot) for chainSpot in spot.spotChain()] for spot in spotList] self.setRowCount(len(chainList)) for row in range(len(chainList)): columns = len(chainList[row]) * 2 - 1 if columns > self.columnCount(): self.setColumnCount(columns) for col in range(len(chainList[row])): item = chainList[row][col] if (row == 0 or col >= len(chainList[row - 1]) or item.spot is not chainList[row - 1][col].spot): rowSpan = 1 while (row + rowSpan < len(chainList) and col < len(chainList[row + rowSpan]) and item.spot is chainList[row + rowSpan][col].spot): rowSpan += 1 if col < len(chainList[row]) - 1: arrowItem = QTableWidgetItem('\u25ba') arrowItem.setTextAlignment(Qt.AlignmentFlag.AlignCenter) self.setItem(row, col * 2 + 1, arrowItem) if rowSpan > 1: self.setSpan(row, col * 2 + 1, rowSpan, 1) self.setItem(row, col * 2, item) if rowSpan > 1: self.setSpan(row, col * 2, rowSpan, 1) if item.spot is selSpot: item.selectedSpot = True item.setForeground(QApplication.palette(). brush(QPalette.ColorRole. WindowText)) self.resizeColumnsToContents() def changeSelection(self, item): """Change the current selection to given item bassed on a mouse click. Arguments: item -- the breadcrumb item that was clicked """ selModel = self.treeView.selectionModel() if hasattr(item, 'spot') and not item.selectedSpot: selModel.selectSpots([item.spot]) self.setCursor(Qt.CursorShape.ArrowCursor) def minimumSizeHint(self): """Set a short minimum size fint to allow the display of one row. """ return QSize(super().minimumSizeHint().width(), self.fontInfo().pixelSize() * 3) def mouseMoveEvent(self, event): """Change the mouse pointer if over a clickable item. Arguments: event -- the mouse move event """ item = self.itemAt(event.position().toPoint()) if item and hasattr(item, 'spot') and not item.selectedSpot: self.setCursor(Qt.CursorShape.PointingHandCursor) else: self.setCursor(Qt.CursorShape.ArrowCursor) super().mouseMoveEvent(event) def resizeEvent(self, event): """Update view if was collaped by splitter. """ if ((event.oldSize().height() == 0 and event.size().height()) or (event.oldSize().width() == 0 and event.size().width())): self.updateContents() return super().resizeEvent(event) TreeLine-3.2.1/source/colorset.py000066400000000000000000000276151506556630100167520ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # colorset.py, provides storage/retrieval and dialogs for GUI colors # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITTHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import enum from collections import OrderedDict from PyQt6.QtCore import pyqtSignal, Qt, QEvent, QObject from PyQt6.QtGui import QColor, QFontMetrics, QPalette, QPixmap from PyQt6.QtWidgets import (QApplication, QColorDialog, QComboBox, QDialog, QFrame, QGroupBox, QHBoxLayout, QLabel, QGridLayout, QPushButton, QVBoxLayout) import globalref roles = OrderedDict([('Window', _('Dialog background color')), ('WindowText', _('Dialog text color')), ('Base', _('Text widget background color')), ('Text', _('Text widget foreground color')), ('Highlight', _('Selected item background color')), ('HighlightedText', _('Selected item text color')), ('Link', _('Link text color')), ('ToolTipBase', _('Tool tip background color')), ('ToolTipText', _('Tool tip foreground color')), ('Button', _('Button background color')), ('ButtonText', _('Button text color')), ('Text-Disabled', _('Disabled text foreground color')), ('ButtonText-Disabled', _('Disabled button text color'))]) ThemeSetting = enum.IntEnum('ThemeSetting', 'system light dark custom') lightColors = {'Window': '#efefef', 'WindowText': '#000000', 'Base': '#ffffff', 'Text': '#000000', 'Highlight': '#308cc6', 'HighlightedText': '#ffffff', 'Link': '#0000ff', 'ToolTipBase': '#ffffdc', 'ToolTipText': '#000000', 'Button': '#efefef', 'ButtonText': '#000000', 'Text-Disabled': '#bebebe', 'ButtonText-Disabled': '#bebebe'} darkColors = {'Window': '#353535', 'WindowText': '#ffffff', 'Base': '#191919', 'Text': '#ffffff', 'Highlight': '#2a82da', 'HighlightedText': '#000000', 'Link': '#2a82da', 'ToolTipBase': '#000080', 'ToolTipText': '#c0c0c0', 'Button': '#353535', 'ButtonText': '#ffffff', 'Text-Disabled': '#808080', 'ButtonText-Disabled': '#808080'} class ColorSet: """Stores color settings and provides dialogs for user changes. """ def __init__(self): """Initialize colors settings from the system or from options. """ self.sysPalette = QApplication.palette() self.colors = [Color(roleKey) for roleKey in roles.keys()] self.theme = ThemeSetting[globalref.miscOptions['ColorTheme']] for color in self.colors: color.colorChanged.connect(self.setCustomTheme) color.setFromPalette(self.sysPalette) if self.theme == ThemeSetting.light: color.setFromTheme(lightColors) elif self.theme == ThemeSetting.dark: color.setFromTheme(darkColors) elif self.theme == ThemeSetting.custom: color.setFromOption() def setAppColors(self): """Set application to current colors. """ newPalette = QApplication.palette() for color in self.colors: color.updatePalette(newPalette) QApplication.setPalette(newPalette) def showDialog(self, parent): """Show a dialog for user color changes. Return True if changes were made. Arguments: parent -- the parent widget for the dialog """ dialog = QDialog(parent) dialog.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowSystemMenuHint) dialog.setWindowTitle(_('Color Settings')) topLayout = QVBoxLayout(dialog) dialog.setLayout(topLayout) themeBox = QGroupBox(_('Color Theme'), dialog) topLayout.addWidget(themeBox) themeLayout = QVBoxLayout(themeBox) self.themeControl = QComboBox(dialog) self.themeControl.addItem(_('Default system theme'), ThemeSetting.system) self.themeControl.addItem(_('Light theme'), ThemeSetting.light) self.themeControl.addItem(_('Dark theme'), ThemeSetting.dark) self.themeControl.addItem(_('Custom theme'), ThemeSetting.custom) self.themeControl.setCurrentIndex(self.themeControl. findData(self.theme)) self.themeControl.currentIndexChanged.connect(self.updateThemeSetting) themeLayout.addWidget(self.themeControl) self.groupBox = QGroupBox(dialog) self.setBoxTitle() topLayout.addWidget(self.groupBox) gridLayout = QGridLayout(self.groupBox) row = 0 for color in self.colors: gridLayout.addWidget(color.getLabel(), row, 0) gridLayout.addWidget(color.getSwatch(), row, 1) row += 1 ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) okButton = QPushButton(_('&OK'), dialog) ctrlLayout.addWidget(okButton) okButton.clicked.connect(dialog.accept) cancelButton = QPushButton(_('&Cancel'), dialog) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(dialog.reject) if dialog.exec() == QDialog.DialogCode.Accepted: self.theme = ThemeSetting(self.themeControl.currentData()) globalref.miscOptions.changeValue('ColorTheme', self.theme.name) if self.theme == ThemeSetting.system: QApplication.setPalette(self.sysPalette) else: # named theme or custom if self.theme == ThemeSetting.custom: for color in self.colors: color.updateOption() self.setAppColors() globalref.miscOptions.writeFile() else: for color in self.colors: color.setFromPalette(self.sysPalette) if self.theme == ThemeSetting.light: color.setFromTheme(lightColors) elif self.theme == ThemeSetting.dark: color.setFromTheme(darkColors) elif self.theme == ThemeSetting.custom: color.setFromOption() def setBoxTitle(self): """Set title of group box to standard or custom. """ if self.themeControl.currentData() == ThemeSetting.custom: title = _('Custom Colors') else: title = _('Theme Colors') self.groupBox.setTitle(title) def updateThemeSetting(self): """Update the colors based on a theme control change. """ if self.themeControl.currentData() == ThemeSetting.system: for color in self.colors: color.setFromPalette(self.sysPalette) color.changeSwatchColor() elif self.themeControl.currentData() == ThemeSetting.light: for color in self.colors: color.setFromTheme(lightColors) color.changeSwatchColor() elif self.themeControl.currentData() == ThemeSetting.dark: for color in self.colors: color.setFromTheme(darkColors) color.changeSwatchColor() else: for color in self.colors: color.setFromOption() color.changeSwatchColor() self.setBoxTitle() def setCustomTheme(self): """Set to custom theme setting after user color change. """ if self.themeControl.currentData != ThemeSetting.custom: self.themeControl.blockSignals(True) self.themeControl.setCurrentIndex(2) self.themeControl.blockSignals(False) self.setBoxTitle() class Color(QObject): """Stores a single color setting for a role. """ colorChanged = pyqtSignal() def __init__(self, roleKey, parent=None): """Initialize a Color. Arguments: roleKey -- the text name of the color role parent -- a parent object if given """ super().__init__(parent) self.roleKey = roleKey if '-' in roleKey: roleStr, groupStr = roleKey.split('-') self.group = eval('QPalette.ColorGroup.' + groupStr) else: roleStr = roleKey self.group = None self.role = eval('QPalette.ColorRole.' + roleStr) self.currentColor = None self.swatch = None def setFromPalette(self, palette): """Set the color based on the given palette. Arguments: palette -- the palette that defines the color """ if self.group: self.currentColor = palette.color(self.group, self.role) else: self.currentColor = palette.color(self.role) def setFromOption(self): """Set color based on the option setting. """ colorStr = globalref.miscOptions[self.roleKey + 'Color'] color = QColor(colorStr) if color.isValid(): self.currentColor = color def setFromTheme(self, theme): """Set color based on the given theme dictionary. Arguments: theme -- a theme dictionary that defines the color """ self.currentColor = QColor(theme[self.roleKey]) def updateOption(self): """Set the option to the current color. """ if self.currentColor: globalref.miscOptions.changeValue(self.roleKey + 'Color', self.currentColor.name()) def updatePalette(self, palette): """Set the role in the given palette to the current color. Arguments: palette -- the palette that gets set with the color """ if self.group: palette.setColor(self.group, self.role, self.currentColor) else: palette.setColor(self.role, self.currentColor) def getLabel(self): """Return a label for this role in a dialog. """ return QLabel(roles[self.roleKey]) def getSwatch(self): """Return a label color swatch with the current color. """ self.swatch = QLabel() self.changeSwatchColor() self.swatch.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Raised) self.swatch.setLineWidth(3) self.swatch.installEventFilter(self) return self.swatch def changeSwatchColor(self): """Set swatch to currentColor. """ height = QFontMetrics(self.swatch.font()).height() pixmap = QPixmap(3 * height, height) pixmap.fill(self.currentColor) self.swatch.setPixmap(pixmap) def eventFilter(self, obj, event): """Handle mouse clicks on swatches. Arguments: obj -- the object to handle events for event -- the specific event """ if (obj == self.swatch and event.type() == QEvent.Type.MouseButtonRelease): color = QColorDialog.getColor(self.currentColor, QApplication.activeWindow(), _('Select {0} color'). format(self.roleKey)) if color.isValid() and color != self.currentColor: self.currentColor = color self.changeSwatchColor() self.colorChanged.emit() return True return False TreeLine-3.2.1/source/conditional.py000066400000000000000000000653131506556630100174200ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # conditional.py, provides a class to store field comparison functions # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import enum from PyQt6.QtCore import QSize, Qt, pyqtSignal from PyQt6.QtWidgets import (QComboBox, QDialog, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QListWidget, QPushButton, QSizePolicy, QVBoxLayout) import treeformats import configdialog import undo import globalref _operators = ['==', '<', '<=', '>', '>=', '!=', N_('starts with'), N_('ends with'), N_('contains'), N_('True'), N_('False')] _functions = {'==': '__eq__', '<': '__lt__', '<=': '__le__', '>': '__gt__', '>=': '__ge__', '!=': '__ne__', 'starts with': 'startswith', 'ends with': 'endswith', 'contains': 'contains', 'True': 'true', 'False': 'false'} _boolOper = [N_('and'), N_('or')] _allTypeEntry = _('[All Types]') _parseRe = re.compile(r'((?:and)|(?:or)) (\S+) (.+?) ' r'(?:(? "othervalue"' Arguments: conditionStr -- the condition string to set nodeFormatName -- if name is set, restricts matches to type family """ self.conditionLines = [] conditionStr = 'and ' + conditionStr for boolOper, fieldName, oper, value in _parseRe.findall(conditionStr): value = value.replace('\\"', '"').replace('\\\\', '\\') self.conditionLines.append(ConditionLine(boolOper, fieldName, oper, value)) self.origNodeFormatName = nodeFormatName self.nodeFormatNames = set() if nodeFormatName: self.nodeFormatNames.add(nodeFormatName) nodeFormats = (globalref.mainControl.activeControl.structure. treeFormats) for nodeType in nodeFormats[nodeFormatName].derivedTypes: self.nodeFormatNames.add(nodeType.name) def evaluate(self, node): """Evaluate this condition and return True or False. Arguments: node -- the node to check for a field match """ if (self.nodeFormatNames and node.formatRef.name not in self.nodeFormatNames): return False result = True for conditon in self.conditionLines: result = conditon.evaluate(node, result) return result def conditionStr(self): """Return the condition string for this condition set. """ return ' '.join([cond.conditionStr() for cond in self.conditionLines])[4:] def renameFields(self, oldName, newName): """Rename the any fields found in condition lines. Arguments: oldName -- the previous field name newName -- the updated field name """ for condition in self.conditionLines: if condition.fieldName == oldName: condition.fieldName = newName def removeField(self, fieldname): """Remove conditional lines referencing the given field. Arguments: fieldname -- the field name to be removed """ for condition in self.conditionLines[:]: if condition.fieldName == fieldname: self.conditionLines.remove(condition) def __len__(self): """Return the number of conditions for truth testing. """ return len(self.conditionLines) class ConditionLine: """Stores & evaluates a portion of a conditional comparison. """ def __init__(self, boolOper, fieldName, oper, value): """Initialize the condition line. Arguments: boolOper -- a string for combining previous lines ('and' or 'or') fieldName -- the field name to evaluate oper -- the operator string value -- the string for comparison """ self.boolOper = boolOper self.fieldName = fieldName self.oper = oper self.value = value def evaluate(self, node, prevResult=True): """Evaluate this line and return True or False. Arguments: node -- the node to check for a field match prevResult -- the result to combine with the boolOper """ try: field = node.formatRef.fieldDict[self.fieldName] except KeyError: if self.boolOper == 'and': return False return prevResult dataStr = field.compareValue(node) value = field.adjustedCompareValue(self.value) try: func = getattr(dataStr, _functions[self.oper]) except AttributeError: dataStr = StringOps(dataStr) func = getattr(dataStr, _functions[self.oper]) value = str(value) if self.boolOper == 'and': return prevResult and func(value) else: return prevResult or func(value) def conditionStr(self): """Return the text line for this condition. """ value = self.value.replace('\\', '\\\\').replace('"', '\\"') return '{0} {1} {2} "{3}"'.format(self.boolOper, self.fieldName, self.oper, value) class StringOps(str): """A string class with extra comparison functions. """ def __new__(cls, initStr=''): """Return the str object. Arguments: initStr -- the initial string value """ return str.__new__(cls, initStr) def contains(self, substr): """Return True if self contains substr. Arguments: substr -- the substring to check """ return self.find(substr) != -1 def true(self, other=''): """Always return True. Arguments: other -- unused placeholder """ return True def false(self, other=''): """Always return False. Arguments: other -- unused placeholder """ return False FindDialogType = enum.Enum('FindDialogType', 'typeDialog findDialog filterDialog') class ConditionDialog(QDialog): """Dialog for defining field condition tests. Used for defining conditional types (modal), for finding by condition (nonmodal) and for filtering by condition (nonmodal). """ dialogShown = pyqtSignal(bool) def __init__(self, dialogType, caption, nodeFormat=None, parent=None): """Create the conditional dialog. Arguments: dialogType -- either typeDialog, findDialog or filterDialog caption -- the window title for this dialog nodeFormat -- the current node format for the typeDialog parent -- the parent overall dialog """ super().__init__(parent) self.setWindowTitle(caption) self.dialogType = dialogType self.ruleList = [] self.combiningBoxes = [] self.typeCombo = None self.resultLabel = None self.endFilterButton = None self.fieldNames = [] if nodeFormat: self.fieldNames = nodeFormat.fieldNames() topLayout = QVBoxLayout(self) if dialogType == FindDialogType.typeDialog: self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) else: self.setAttribute(Qt.WidgetAttribute.WA_QuitOnClose, False) self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowStaysOnTopHint) typeBox = QGroupBox(_('Node Type')) topLayout.addWidget(typeBox) typeLayout = QVBoxLayout(typeBox) self.typeCombo = QComboBox() typeLayout.addWidget(self.typeCombo) self.typeCombo.currentIndexChanged.connect(self.updateDataType) self.mainLayout = QVBoxLayout() topLayout.addLayout(self.mainLayout) upCtrlLayout = QHBoxLayout() topLayout.addLayout(upCtrlLayout) addButton = QPushButton(_('&Add New Rule')) upCtrlLayout.addWidget(addButton) addButton.clicked.connect(self.addNewRule) self.removeButton = QPushButton(_('&Remove Rule')) upCtrlLayout.addWidget(self.removeButton) self.removeButton.clicked.connect(self.removeRule) upCtrlLayout.addStretch() if dialogType == FindDialogType.typeDialog: okButton = QPushButton(_('&OK')) upCtrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) upCtrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) else: self.removeButton.setEnabled(False) saveBox = QGroupBox(_('Saved Rules')) topLayout.addWidget(saveBox) saveLayout = QVBoxLayout(saveBox) self.saveListBox = SmallListWidget() saveLayout.addWidget(self.saveListBox) self.saveListBox.itemDoubleClicked.connect(self.loadSavedRule) nameLayout = QHBoxLayout() saveLayout.addLayout(nameLayout) label = QLabel(_('Name:')) nameLayout.addWidget(label) self.saveNameEdit = QLineEdit() nameLayout.addWidget(self.saveNameEdit) self.saveNameEdit.textChanged.connect(self.updateSaveEnable) saveButtonLayout = QHBoxLayout() saveLayout.addLayout(saveButtonLayout) self.loadSavedButton = QPushButton(_('&Load')) saveButtonLayout.addWidget(self.loadSavedButton) self.loadSavedButton.clicked.connect(self.loadSavedRule) self.saveButton = QPushButton(_('&Save')) saveButtonLayout.addWidget(self.saveButton) self.saveButton.clicked.connect(self.saveRule) self.saveButton.setEnabled(False) self.delSavedButton = QPushButton(_('&Delete')) saveButtonLayout.addWidget(self.delSavedButton) self.delSavedButton.clicked.connect(self.deleteRule) saveButtonLayout.addStretch() if dialogType == FindDialogType.findDialog: self.resultLabel = QLabel() topLayout.addWidget(self.resultLabel) lowCtrlLayout = QHBoxLayout() topLayout.addLayout(lowCtrlLayout) if dialogType == FindDialogType.findDialog: previousButton = QPushButton(_('Find &Previous')) lowCtrlLayout.addWidget(previousButton) previousButton.clicked.connect(self.findPrevious) nextButton = QPushButton(_('Find &Next')) nextButton.setDefault(True) lowCtrlLayout.addWidget(nextButton) nextButton.clicked.connect(self.findNext) else: filterButton = QPushButton(_('&Filter')) lowCtrlLayout.addWidget(filterButton) filterButton.clicked.connect(self.startFilter) self.endFilterButton = QPushButton(_('&End Filter')) lowCtrlLayout.addWidget(self.endFilterButton) self.endFilterButton.setEnabled(False) self.endFilterButton.clicked.connect(self.endFilter) lowCtrlLayout.addStretch() closeButton = QPushButton(_('&Close')) lowCtrlLayout.addWidget(closeButton) closeButton.clicked.connect(self.close) origTypeName = nodeFormat.name if nodeFormat else '' self.loadTypeNames(origTypeName) self.loadSavedNames() self.ruleList.append(ConditionRule(1, self.fieldNames)) self.mainLayout.addWidget(self.ruleList[0]) def addNewRule(self, checked=False, combineBool='and'): """Add a new empty rule to the dialog. Arguments: checked -- unused placekeeper variable for signal combineBool -- the boolean op for combining with the previous rule """ if self.ruleList: boolBox = QComboBox() boolBox.setEditable(False) self.combiningBoxes.append(boolBox) boolBox.addItems([_(op) for op in _boolOper]) if combineBool != 'and': boolBox.setCurrentIndex(1) self.mainLayout.insertWidget(len(self.ruleList) * 2 - 1, boolBox, 0, Qt.AlignmentFlag.AlignHCenter) rule = ConditionRule(len(self.ruleList) + 1, self.fieldNames) self.ruleList.append(rule) self.mainLayout.insertWidget(len(self.ruleList) * 2 - 2, rule) self.removeButton.setEnabled(True) def removeRule(self): """Remove the last rule from the dialog. """ if self.ruleList: if self.combiningBoxes: self.combiningBoxes[-1].hide() del self.combiningBoxes[-1] self.ruleList[-1].hide() del self.ruleList[-1] if self.dialogType == FindDialogType.typeDialog: self.removeButton.setEnabled(len(self.ruleList) > 0) else: self.removeButton.setEnabled(len(self.ruleList) > 1) def clearRules(self): """Remove all rules from the dialog and add default rule. """ for box in self.combiningBoxes: box.hide() for rule in self.ruleList: rule.hide() self.combiningBoxes = [] self.ruleList = [ConditionRule(1, self.fieldNames)] self.mainLayout.insertWidget(0, self.ruleList[0]) self.removeButton.setEnabled(True) def setCondition(self, conditional, typeName=''): """Set rule values to match the given conditional. Arguments: conditional -- the Conditional class to match typeName -- an optional type name used with some dialog types """ if self.typeCombo: if typeName: self.typeCombo.setCurrentIndex(self.typeCombo. findText(typeName)) else: self.typeCombo.setCurrentIndex(0) while len(self.ruleList) > 1: self.removeRule() if conditional: self.ruleList[0].setCondition(conditional.conditionLines[0]) for conditionLine in conditional.conditionLines[1:]: self.addNewRule(combineBool=conditionLine.boolOper) self.ruleList[-1].setCondition(conditionLine) def conditional(self): """Return a Conditional instance for the current settings. """ combineBools = [0] + [boolBox.currentIndex() for boolBox in self.combiningBoxes] typeName = self.typeCombo.currentText() if self.typeCombo else '' if typeName == _allTypeEntry: typeName = '' conditional = Conditional('', typeName) for boolIndex, rule in zip(combineBools, self.ruleList): condition = rule.conditionLine() if boolIndex != 0: condition.boolOper = 'or' conditional.conditionLines.append(condition) return conditional def loadTypeNames(self, origTypeName=''): """Load format type names into combo box. Arguments: origTypeName -- a starting type name if given """ if not origTypeName: origTypeName = self.typeCombo.currentText() nodeFormats = globalref.mainControl.activeControl.structure.treeFormats self.typeCombo.blockSignals(True) self.typeCombo.clear() self.typeCombo.addItem(_allTypeEntry) typeNames = nodeFormats.typeNames() self.typeCombo.addItems(typeNames) if origTypeName and origTypeName != _allTypeEntry: try: self.typeCombo.setCurrentIndex(typeNames.index(origTypeName) + 1) except ValueError: if self.endFilterButton and self.endFilterButton.isEnabled(): self.endFilter() self.clearRules() self.typeCombo.blockSignals(False) self.updateDataType() def updateDataType(self): """Update the node format based on a data type change. """ typeName = self.typeCombo.currentText() if not typeName: return nodeFormats = globalref.mainControl.activeControl.structure.treeFormats if typeName == _allTypeEntry: fieldNameSet = set() for typeFormat in nodeFormats.values(): fieldNameSet.update(typeFormat.fieldNames()) self.fieldNames = sorted(list(fieldNameSet)) else: self.fieldNames = nodeFormats[typeName].fieldNames() for rule in self.ruleList: currentField = rule.conditionLine().fieldName if currentField not in self.fieldNames: if self.endFilterButton and self.endFilterButton.isEnabled(): self.endFilter() self.clearRules() break rule.reloadFieldBox(self.fieldNames, currentField) def loadSavedNames(self, updateOtherDialog=False): """Refresh the list of saved rule names. """ selNum = 0 if self.saveListBox.count(): selNum = self.saveListBox.currentRow() self.saveListBox.clear() nodeFormats = globalref.mainControl.activeControl.structure.treeFormats savedRules = nodeFormats.savedConditions() ruleNames = sorted(list(savedRules.keys())) if ruleNames: self.saveListBox.addItems(ruleNames) if selNum >= len(ruleNames): selNum = len(ruleNames) - 1 self.saveListBox.setCurrentRow(selNum) self.loadSavedButton.setEnabled(len(ruleNames) > 0) self.delSavedButton.setEnabled(len(ruleNames) > 0) if updateOtherDialog: if (self != globalref.mainControl.findConditionDialog and globalref.mainControl.findConditionDialog and globalref.mainControl.findConditionDialog.isVisible()): globalref.mainControl.findConditionDialog.loadSavedNames() elif (self != globalref.mainControl.filterConditionDialog and globalref.mainControl.filterConditionDialog and globalref.mainControl.filterConditionDialog .isVisible()): globalref.mainControl.filterConditionDialog.loadSavedNames() def updateSaveEnable(self): """Set the save rule button enabled based on save name entry. """ self.saveButton.setEnabled(len(self.saveNameEdit.text())) def updateFilterControls(self): """Set filter button status based on active window changes. """ window = globalref.mainControl.activeControl.activeWindow if window.treeFilterView: filterView = window.treeFilterView conditional = filterView.conditionalFilter self.setCondition(conditional, conditional.origNodeFormatName) self.endFilterButton.setEnabled(True) else: self.endFilterButton.setEnabled(False) def loadSavedRule(self): """Load the current saved rule into the dialog. """ nodeFormats = globalref.mainControl.activeControl.structure.treeFormats savedRules = nodeFormats.savedConditions() ruleName = self.saveListBox.currentItem().text() conditional = savedRules[ruleName] self.setCondition(conditional, conditional.origNodeFormatName) def saveRule(self): """Save the current rule settings. """ name = self.saveNameEdit.text() self.saveNameEdit.setText('') treeStructure = globalref.mainControl.activeControl.structure undo.FormatUndo(treeStructure.undoList, treeStructure.treeFormats, treeformats.TreeFormats()) typeName = self.typeCombo.currentText() if typeName == _allTypeEntry: nodeFormat = treeStructure.treeFormats else: nodeFormat = treeStructure.treeFormats[typeName] nodeFormat.savedConditionText[name] = (self.conditional(). conditionStr()) self.loadSavedNames(True) self.saveListBox.setCurrentItem(self.saveListBox. findItems(name, Qt.MatchFlag.MatchExactly)[0]) globalref.mainControl.activeControl.setModified() def deleteRule(self): """Remove the current saved rule. """ treeStructure = globalref.mainControl.activeControl.structure nodeFormats = treeStructure.treeFormats undo.FormatUndo(treeStructure.undoList, nodeFormats, treeformats.TreeFormats()) savedRules = nodeFormats.savedConditions() ruleName = self.saveListBox.currentItem().text() conditional = savedRules[ruleName] if conditional.origNodeFormatName: typeFormat = nodeFormats[conditional. origNodeFormatName] del typeFormat.savedConditionText[ruleName] else: del nodeFormats.savedConditionText[ruleName] self.loadSavedNames(True) globalref.mainControl.activeControl.setModified() def find(self, forward=True): """Find another match in the indicated direction. Arguments: forward -- next if True, previous if False """ self.resultLabel.setText('') conditional = self.conditional() control = globalref.mainControl.activeControl if not control.findNodesByCondition(conditional, forward): self.resultLabel.setText(_('No conditional matches were found')) def findPrevious(self): """Find the previous match. """ self.find(False) def findNext(self): """Find the next match. """ self.find(True) def startFilter(self): """Start filtering nodes. """ window = globalref.mainControl.activeControl.activeWindow filterView = window.filterView() filterView.conditionalFilter = self.conditional() filterView.updateContents() self.endFilterButton.setEnabled(True) def endFilter(self): """Stop filtering nodes. """ window = globalref.mainControl.activeControl.activeWindow window.removeFilterView() self.endFilterButton.setEnabled(False) def closeEvent(self, event): """Signal that the dialog is closing. Arguments: event -- the close event """ self.dialogShown.emit(False) def reject(self): """Handle use of escape key to close this dialog. """ self.close() class ConditionRule(QGroupBox): """Group boxes for conditional rules in the ConditionDialog. """ def __init__(self, num, fieldNames, parent=None): """Create the conditional rule group box. Arguments: num -- the sequence number for the title fieldNames -- a list of available field names parent -- the parent dialog """ super().__init__(parent) self.fieldNames = fieldNames self.setTitle(_('Rule {0}').format(num)) layout = QHBoxLayout(self) self.fieldBox = QComboBox() self.fieldBox.setEditable(False) self.fieldBox.addItems(fieldNames) layout.addWidget(self.fieldBox) self.operBox = QComboBox() self.operBox.setEditable(False) self.operBox.addItems([_(op) for op in _operators]) layout.addWidget(self.operBox) self.operBox.currentIndexChanged.connect(self.changeOper) self.editor = QLineEdit() layout.addWidget(self.editor) self.fieldBox.setFocus() def reloadFieldBox(self, fieldNames, currentField=''): """Load the field combo box with a new field list. Arguments: fieldNames -- list of field names to add currentField -- a field name to make current if given """ self.fieldNames = fieldNames self.fieldBox.clear() self.fieldBox.addItems(fieldNames) if currentField: fieldNum = fieldNames.index(currentField) self.fieldBox.setCurrentIndex(fieldNum) self.changeOper() def setCondition(self, conditionLine): """Set values to match the given condition. Arguments: conditionLine -- the ConditionLine to match """ fieldNum = self.fieldNames.index(conditionLine.fieldName) self.fieldBox.setCurrentIndex(fieldNum) operNum = _operators.index(conditionLine.oper) self.operBox.setCurrentIndex(operNum) self.editor.setText(conditionLine.value) def conditionLine(self): """Return a conditionLine for the current settings. """ operTransDict = dict([(_(name), name) for name in _operators]) oper = operTransDict[self.operBox.currentText()] return ConditionLine('and', self.fieldBox.currentText(), oper, self.editor.text()) def changeOper(self): """Set the field available based on an operator change. """ realOp = self.operBox.currentText() not in (_(op) for op in ('True', 'False')) self.editor.setEnabled(realOp) if (not realOp and self.parent().typeCombo.currentText() == _allTypeEntry): realOp = True self.fieldBox.setEnabled(realOp) class SmallListWidget(QListWidget): """ListWidget with a smaller size hint. """ def __init__(self, parent=None): """Initialize the widget. Arguments: parent -- the parent, if given """ super().__init__(parent) def sizeHint(self): """Return smaller height. """ if self.count(): rowHeight = self.sizeHintForRow(0) else: self.addItem('tmp') rowHeight = self.sizeHintForRow(0) self.takeItem(0) newHeight = rowHeight * 3 + self.frameWidth() * 2 return QSize(super().sizeHint().width(), newHeight) TreeLine-3.2.1/source/configdialog.py000066400000000000000000003175611506556630100175470ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # configdialog.py, provides classes for the type configuration dialog # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import copy import operator from PyQt6.QtCore import QPoint, QSize, Qt, pyqtSignal from PyQt6.QtGui import QTextCursor from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QButtonGroup, QCheckBox, QComboBox, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QListView, QListWidget, QListWidgetItem, QMenu, QMessageBox, QPushButton, QScrollArea, QSizePolicy, QSpinBox, QTabWidget, QTextEdit, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget) import nodeformat import fieldformat import icondict import conditional import matheval import globalref class ConfigDialog(QDialog): """Class override for the main config dialog Contains the tabbed pages that handle the actual settings. """ dialogShown = pyqtSignal(bool) treeStruct = None formatsRef = None currentTypeName = '' currentFieldName = '' def __init__(self, parent=None): """Initialize the config dialog. Arguments: parent -- the parent window """ super().__init__(parent) self.setAttribute(Qt.WidgetAttribute.WA_QuitOnClose, False) self.setWindowFlags(Qt.WindowType.Window) self.setWindowTitle(_('Configure Data Types')) self.prevPage = None self.localControl = None self.selectionModel = None topLayout = QVBoxLayout(self) self.setLayout(topLayout) self.tabs = QTabWidget() topLayout.addWidget(self.tabs) typeListPage = TypeListPage(self) self.tabs.addTab(typeListPage, _('T&ype List')) typeConfigPage = TypeConfigPage(self) self.tabs.addTab(typeConfigPage, _('Typ&e Config')) fieldListPage = FieldListPage(self) self.tabs.addTab(fieldListPage, _('Field &List')) fieldConfigPage = FieldConfigPage(self) self.tabs.addTab(fieldConfigPage, _('&Field Config')) outputPage = OutputPage(self) self.tabs.addTab(outputPage, _('O&utput')) self.tabs.currentChanged.connect(self.updatePage) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) self.advancedButton = QPushButton(_('&Show Advanced')) ctrlLayout.addWidget(self.advancedButton) self.advancedButton.setCheckable(True) self.advancedButton.clicked.connect(self.toggleAdavanced) ctrlLayout.addStretch() okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.applyAndClose) self.applyButton = QPushButton(_('&Apply')) ctrlLayout.addWidget(self.applyButton) self.applyButton.clicked.connect(self.applyChanges) self.resetButton = QPushButton(_('&Reset')) ctrlLayout.addWidget(self.resetButton) self.resetButton.clicked.connect(self.reset) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.resetAndClose) def setRefs(self, localControl, resetSelect=False, forceCopy=False): """Set refs to model and formats, then update dialog data. Sets current type to current node's type if resetSelect or if invalid. Sets current field to first field if resetSelect or if invalid. Arguments: localControl -- a reference to the local control resetSelect -- if True, forces reset of current selections forceCopy -- if True, force making a new copy of formats """ self.localControl = localControl ConfigDialog.treeStruct = localControl.structure ConfigDialog.formatsRef = (ConfigDialog.treeStruct. getConfigDialogFormats(forceCopy)) self.selectionModel = localControl.currentSelectionModel() self.updateSelections(resetSelect) self.prevPage = None self.updatePage() self.applyButton.setEnabled(ConfigDialog.formatsRef.configModified) self.resetButton.setEnabled(ConfigDialog.formatsRef.configModified) def updateSelections(self, forceUpdate=False): """Sets current type & current field if invalid or forceUpdate is True. Arguments: forceUpdate -- if True, forces reset of current selections """ if forceUpdate or (ConfigDialog.currentTypeName not in ConfigDialog.formatsRef): try: ConfigDialog.currentTypeName = (self.selectionModel. currentNode().formatRef.name) except AttributeError: # no current node ConfigDialog.currentTypeName = (ConfigDialog.treeStruct. childList[0].formatRef.name) if forceUpdate or (ConfigDialog.currentFieldName not in ConfigDialog.formatsRef[ConfigDialog. currentTypeName].fieldNames()): ConfigDialog.currentFieldName = (ConfigDialog. formatsRef[ConfigDialog. currentTypeName]. fieldNames()[0]) def updatePage(self): """Update new page and advanced button state when changing tabs. """ if self.prevPage: self.prevPage.readChanges() page = self.tabs.currentWidget() self.advancedButton.setEnabled(len(page.advancedWidgets)) page.toggleAdvanced(self.advancedButton.isChecked()) page.updateContent() self.prevPage = page def setModified(self, dummyArg=None, modified=True): """Set the format to a modified status and update the controls. Arguments: dummyArg -- placeholder for unused signal arguments modified -- set to modified if True """ ConfigDialog.formatsRef.configModified = modified self.applyButton.setEnabled(modified) self.resetButton.setEnabled(modified) def toggleAdavanced(self, show): """Toggle the display of advanced widgets in the sub-dialogs. Arguments: show -- show if true, hide if false """ if show: self.advancedButton.setText(_('&Hide Advanced')) else: self.advancedButton.setText(_('&Show Advanced')) page = self.tabs.currentWidget() page.toggleAdvanced(show) def reset(self): """Set the formats back to original settings. """ ConfigDialog.formatsRef = (ConfigDialog.treeStruct. getConfigDialogFormats(True)) self.updateSelections() self.setModified(modified=False) self.prevPage = None self.updatePage() def applyChanges(self): """Apply copied format changes to the main format. Return False if there is a circular math reference. """ self.tabs.currentWidget().readChanges() if ConfigDialog.formatsRef.configModified: try: ConfigDialog.treeStruct.applyConfigDialogFormats() except matheval.CircularMathError: QMessageBox.warning(self, 'TreeLine', _('Error - circular reference in math field equations')) return False self.setModified(modified=False) self.localControl.updateAll() return True def applyAndClose(self): """Apply copied format changes to the main format and close the dialog. """ if self.applyChanges(): self.close() def resetAndClose(self): """Set the formats back to original settings and close the dialog. """ self.reset() self.close() def closeEvent(self, event): """Signal that the dialog is closing. Arguments: event -- the close event """ self.dialogShown.emit(False) def reject(self): """Handle use of escape key to close this dialog. """ self.close() class ConfigPage(QWidget): """Abstract base class for config dialog tabbed pages. """ def __init__(self, parent=None): """Initialize the config dialog page. Arguments: parent -- the parent overall dialog """ super().__init__(parent) self.mainDialogRef = parent self.advancedWidgets = [] def updateContent(self): """Update page contents from current format settings. Base class does nothing. """ pass def readChanges(self): """Make changes to the format for each widget. Base class does nothing. """ pass def changeCurrentType(self, typeName): """Change the current format type based on a signal from lists. Arguments: typeName -- the name of the new current type """ self.readChanges() ConfigDialog.currentTypeName = typeName ConfigDialog.currentFieldName = (ConfigDialog.formatsRef[typeName]. fieldNames()[0]) if type(self) != TypeListPage: # "if" statement added to work around list view selection bug self.updateContent() def changeCurrentField(self, fieldName): """Change the current format field based on a signal from lists. Arguments: fieldName -- the name of the new current field """ self.readChanges() ConfigDialog.currentFieldName = fieldName self.updateContent() def toggleAdvanced(self, show=True): """Toggle the display state of advanced widgets. Arguments: show -- show if true, hide if false """ for widget in self.advancedWidgets: widget.setVisible(show) class TypeListPage(ConfigPage): """Config dialog page with an editable list of node types. """ def __init__(self, parent=None): """Initialize the config dialog page. Arguments: parent -- the parent overall dialog """ super().__init__(parent) topLayout = QVBoxLayout(self) box = QGroupBox(_('Add or Remove Data Types')) topLayout.addWidget(box) horizLayout = QHBoxLayout(box) self.listBox = QListWidget() self.listBox.setSelectionMode(QAbstractItemView.SelectionMode. SingleSelection) horizLayout.addWidget(self.listBox) self.listBox.currentTextChanged.connect(self.changeCurrentType) buttonLayout = QVBoxLayout() horizLayout.addLayout(buttonLayout) newButton = QPushButton(_('&New Type...')) buttonLayout.addWidget(newButton) newButton.clicked.connect(self.newType) copyButton = QPushButton(_('Co&py Type...')) buttonLayout.addWidget(copyButton) copyButton.clicked.connect(self.copyType) renameButton = QPushButton(_('Rena&me Type...')) buttonLayout.addWidget(renameButton) renameButton.clicked.connect(self.renameType) deleteButton = QPushButton(_('&Delete Type')) buttonLayout.addWidget(deleteButton) deleteButton.clicked.connect(self.deleteType) def updateContent(self): """Update page contents from current format settings. """ names = ConfigDialog.formatsRef.typeNames() self.listBox.blockSignals(True) self.listBox.clear() self.listBox.addItems(names) self.listBox.setCurrentRow(names.index(ConfigDialog.currentTypeName)) self.listBox.blockSignals(False) def newType(self): """Create a new type based on button signal. """ dlg = NameEntryDialog(_('Add Type'), _('Enter new type name:'), '', '', ConfigDialog.formatsRef.typeNames(), self) if dlg.exec() == QDialog.DialogCode.Accepted: newFormat = nodeformat.NodeFormat(dlg.text, ConfigDialog.formatsRef, None, True) ConfigDialog.formatsRef[dlg.text] = newFormat ConfigDialog.currentTypeName = dlg.text ConfigDialog.currentFieldName = newFormat.fieldNames()[0] self.updateContent() self.mainDialogRef.setModified() def copyType(self): """Copy selected type based on button signal. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] dlg = NameEntryDialog(_('Copy Type'), _('Enter new type name:'), ConfigDialog.currentTypeName, _('&Derive from original'), ConfigDialog.formatsRef.typeNames(), self) if currentFormat.genericType: dlg.extraCheckBox.setEnabled(False) if dlg.exec() == QDialog.DialogCode.Accepted: newFormat = copy.deepcopy(currentFormat) newFormat.name = dlg.text # avoid using copied reference for parentFormats newFormat.parentFormats = currentFormat.parentFormats ConfigDialog.formatsRef[dlg.text] = newFormat ConfigDialog.currentTypeName = dlg.text if dlg.extraChecked: newFormat.genericType = currentFormat.name ConfigDialog.formatsRef.updateDerivedRefs() self.updateContent() self.mainDialogRef.setModified() def renameType(self): """Rename the selected type based on button signal. """ oldName = ConfigDialog.currentTypeName dlg = NameEntryDialog(_('Rename Type'), _('Rename from {} to:').format(oldName), oldName, '', ConfigDialog.formatsRef.typeNames(), self) if dlg.exec() == QDialog.DialogCode.Accepted: currentType = ConfigDialog.formatsRef[oldName] currentType.name = dlg.text del ConfigDialog.formatsRef[oldName] ConfigDialog.formatsRef[dlg.text] = currentType # reverse the rename dict - find original name (multiple renames) reverseDict = {} for old, new in ConfigDialog.formatsRef.typeRenameDict.items(): reverseDict[new] = old origName = reverseDict.get(oldName, oldName) ConfigDialog.formatsRef.typeRenameDict[origName] = dlg.text if oldName in ConfigDialog.formatsRef.fieldRenameDict: ConfigDialog.formatsRef.fieldRenameDict[dlg.text] = \ ConfigDialog.formatsRef.fieldRenameDict[oldName] del ConfigDialog.formatsRef.fieldRenameDict[oldName] for nodeType in ConfigDialog.formatsRef.values(): if nodeType.childType == oldName: nodeType.childType = dlg.text if nodeType.genericType == oldName: nodeType.genericType = dlg.text if oldName in nodeType.childTypeLimit: nodeType.childTypeLimit.remove(oldName) nodeType.childTypeLimit.add(dlg.text) ConfigDialog.currentTypeName = dlg.text self.updateContent() self.mainDialogRef.setModified() def deleteType(self): """Delete the selected type based on button signal. """ # reverse the rename dict - find original name (before any rename) reverseDict = {} for old, new in ConfigDialog.formatsRef.typeRenameDict.items(): reverseDict[new] = old origName = reverseDict.get(ConfigDialog.currentTypeName, ConfigDialog.currentTypeName) if ConfigDialog.treeStruct.usesType(origName): QMessageBox.warning(self, 'TreeLine', _('Cannot delete data type being used by nodes')) return del ConfigDialog.formatsRef[ConfigDialog.currentTypeName] if origName != ConfigDialog.currentTypeName: del ConfigDialog.formatsRef.typeRenameDict[origName] for nodeType in ConfigDialog.formatsRef.values(): if nodeType.childType == ConfigDialog.currentTypeName: nodeType.childType = '' if nodeType.genericType == ConfigDialog.currentTypeName: nodeType.genericType = '' nodeType.conditional = None nodeType.childTypeLimit.discard(ConfigDialog.currentTypeName) ConfigDialog.formatsRef.updateDerivedRefs() ConfigDialog.currentTypeName = ConfigDialog.formatsRef.typeNames()[0] ConfigDialog.currentFieldName = ConfigDialog.formatsRef[ConfigDialog. currentTypeName].fieldNames()[0] self.updateContent() self.mainDialogRef.setModified() _noTypeSetName = _('[None]', 'no type set') class TypeConfigPage(ConfigPage): """Config dialog page to change parmaters of a node type. """ def __init__(self, parent=None): """Initialize the config dialog page. Arguments: parent -- the parent overall dialog """ super().__init__(parent) topLayout = QGridLayout(self) typeBox = QGroupBox(_('&Data Type')) topLayout.addWidget(typeBox, 0, 0) typeLayout = QVBoxLayout(typeBox) self.typeCombo = QComboBox() typeLayout.addWidget(self.typeCombo) self.typeCombo.currentTextChanged.connect(self.changeCurrentType) childBox = QGroupBox(_('Default Child &Type')) topLayout.addWidget(childBox, 0, 1) childLayout = QVBoxLayout(childBox) self.childCombo = QComboBox() childLayout.addWidget(self.childCombo) self.childCombo.currentIndexChanged.connect(self.mainDialogRef. setModified) iconBox = QGroupBox(_('Icon')) topLayout.addWidget(iconBox, 1, 1) iconLayout = QHBoxLayout(iconBox) self.iconImage = QLabel() iconLayout.addWidget(self.iconImage) self.iconImage.setAlignment(Qt.AlignmentFlag.AlignCenter) iconButton = QPushButton(_('Change &Icon')) iconLayout.addWidget(iconButton) iconButton.clicked.connect(self.changeIcon) optionsBox = QGroupBox(_('Output Options')) topLayout.addWidget(optionsBox, 1, 0, 2, 1) optionsLayout = QVBoxLayout(optionsBox) self.blanksButton = QCheckBox(_('Add &blank lines between ' 'nodes')) optionsLayout.addWidget(self.blanksButton) self.blanksButton.toggled.connect(self.mainDialogRef.setModified) self.htmlButton = QCheckBox(_('Allow &HTML rich text in format')) optionsLayout.addWidget(self.htmlButton) self.htmlButton.toggled.connect(self.mainDialogRef.setModified) self.bulletButton = QCheckBox(_('Add text bullet&s')) optionsLayout.addWidget(self.bulletButton) self.bulletButton.toggled.connect(self.changeUseBullets) self.tableButton = QCheckBox(_('Use a table for field &data')) optionsLayout.addWidget(self.tableButton) self.tableButton.toggled.connect(self.changeUseTable) # advanced widgets outputSepBox = QGroupBox(_('Combination && Child List Output ' '&Separator')) topLayout.addWidget(outputSepBox, 2, 1) self.advancedWidgets.append(outputSepBox) outputSepLayout = QVBoxLayout(outputSepBox) self.outputSepEdit = QLineEdit() outputSepLayout.addWidget(self.outputSepEdit) sizePolicy = self.outputSepEdit.sizePolicy() sizePolicy.setHorizontalPolicy(QSizePolicy.Policy.Preferred) self.outputSepEdit.setSizePolicy(sizePolicy) self.outputSepEdit.textEdited.connect(self.mainDialogRef.setModified) genericBox = QGroupBox(_('Derived from &Generic Type')) topLayout.addWidget(genericBox, 3, 0) self.advancedWidgets.append(genericBox) genericLayout = QVBoxLayout(genericBox) self.genericCombo = QComboBox() genericLayout.addWidget(self.genericCombo) self.genericCombo.currentIndexChanged.connect(self.setConditionAvail) self.genericCombo.currentIndexChanged.connect(self.mainDialogRef. setModified) conditionBox = QGroupBox(_('Automatic Types')) topLayout.addWidget(conditionBox, 3, 1) self.advancedWidgets.append(conditionBox) conditionLayout = QVBoxLayout(conditionBox) self.conditionButton = QPushButton() conditionLayout.addWidget(self.conditionButton) self.conditionButton.clicked.connect(self.showConditionDialog) typeLimitBox = QGroupBox(_('Child Type Limits')) topLayout.addWidget(typeLimitBox, 4, 0) self.advancedWidgets.append(typeLimitBox) typeLimitLayout = QVBoxLayout(typeLimitBox) self.typeLimitCombo = TypeLimitCombo() typeLimitLayout.addWidget(self.typeLimitCombo) self.typeLimitCombo.limitChanged.connect(self.mainDialogRef. setModified) topLayout.setRowStretch(5, 1) def updateContent(self): """Update page contents from current format settings. """ typeNames = ConfigDialog.formatsRef.typeNames() self.typeCombo.blockSignals(True) self.typeCombo.clear() self.typeCombo.addItems(typeNames) self.typeCombo.setCurrentIndex(typeNames.index(ConfigDialog. currentTypeName)) self.typeCombo.blockSignals(False) currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] self.childCombo.blockSignals(True) self.childCombo.clear() self.childCombo.addItem(_noTypeSetName) self.childCombo.addItems(typeNames) try: childItem = typeNames.index(currentFormat.childType) + 1 except ValueError: childItem = 0 self.childCombo.setCurrentIndex(childItem) self.childCombo.blockSignals(False) icon = globalref.treeIcons.getIcon(currentFormat.iconName, True) if icon: self.iconImage.setPixmap(icon.pixmap(16, 16)) else: self.iconImage.setText(_('None')) self.blanksButton.blockSignals(True) self.blanksButton.setChecked(currentFormat.spaceBetween) self.blanksButton.blockSignals(False) self.htmlButton.blockSignals(True) self.htmlButton.setChecked(currentFormat.formatHtml) self.htmlButton.blockSignals(False) self.bulletButton.blockSignals(True) self.bulletButton.setChecked(currentFormat.useBullets) self.bulletButton.blockSignals(False) self.tableButton.blockSignals(True) self.tableButton.setChecked(currentFormat.useTables) self.tableButton.blockSignals(False) self.htmlButton.setEnabled(not currentFormat.useBullets and not currentFormat.useTables) self.outputSepEdit.setText(currentFormat.outputSeparator) self.genericCombo.blockSignals(True) self.genericCombo.clear() self.genericCombo.addItem(_noTypeSetName) genTypeNames = [name for name in typeNames if name != ConfigDialog.currentTypeName and not ConfigDialog.formatsRef[name].genericType] self.genericCombo.addItems(genTypeNames) try: generic = genTypeNames.index(currentFormat.genericType) + 1 except ValueError: generic = 0 self.genericCombo.setCurrentIndex(generic) self.genericCombo.blockSignals(False) self.setConditionAvail() self.typeLimitCombo.updateLists(typeNames, currentFormat.childTypeLimit) def changeIcon(self): """Show the change icon dialog based on a button press. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] dlg = IconSelectDialog(currentFormat, self) if (dlg.exec() == QDialog.DialogCode.Accepted and dlg.currentIconName != currentFormat.iconName): currentFormat.iconName = dlg.currentIconName self.mainDialogRef.setModified() self.updateContent() def changeUseBullets(self, checked=True): """Change setting to use bullets for output. Does not allow bullets and table to both be checked, and automatically checks use HTML. Arguments: checked -- True if bullets are selected """ if checked: self.tableButton.setChecked(False) self.htmlButton.setChecked(True) self.htmlButton.setEnabled(not checked) self.mainDialogRef.setModified() def changeUseTable(self, checked=True): """Change setting to use tables for output. Does not allow bullets and table to both be checked, and automatically checks use HTML. Arguments: checked -- True if tables are selected """ if checked: self.bulletButton.setChecked(False) self.htmlButton.setChecked(True) self.htmlButton.setEnabled(not checked) self.mainDialogRef.setModified() def setConditionAvail(self): """Enable conditional button if generic or dervived type. Set button text based on presence of conditions. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] if self.genericCombo.currentIndex() > 0 or currentFormat.derivedTypes: self.conditionButton.setEnabled(True) if currentFormat.conditional: self.conditionButton.setText(_('Modify Co&nditional Types')) return else: self.conditionButton.setEnabled(False) self.conditionButton.setText(_('Create Co&nditional Types')) def showConditionDialog(self): """Show the dialog to create or modify conditional types. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] dialog = conditional.ConditionDialog(conditional.FindDialogType. typeDialog, _('Set Types Conditionally'), currentFormat) if currentFormat.conditional: dialog.setCondition(currentFormat.conditional) if dialog.exec() == QDialog.DialogCode.Accepted: currentFormat.conditional = dialog.conditional() if not currentFormat.conditional: currentFormat.conditional = None ConfigDialog.formatsRef.updateDerivedRefs() self.mainDialogRef.setModified() self.updateContent() def readChanges(self): """Make changes to the format for each widget. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] currentFormat.childType = self.childCombo.currentText() if currentFormat.childType == _noTypeSetName: currentFormat.childType = '' currentFormat.outputSeparator = self.outputSepEdit.text() prevGenericType = currentFormat.genericType currentFormat.genericType = self.genericCombo.currentText() if currentFormat.genericType == _noTypeSetName: currentFormat.genericType = '' if currentFormat.genericType != prevGenericType: ConfigDialog.formatsRef.updateDerivedRefs() currentFormat.updateFromGeneric(formatsRef=ConfigDialog.formatsRef) if ConfigDialog.currentFieldName not in currentFormat.fieldNames(): ConfigDialog.currentFieldName = currentFormat.fieldNames()[0] currentFormat.spaceBetween = self.blanksButton.isChecked() currentFormat.formatHtml = self.htmlButton.isChecked() currentFormat.childTypeLimit = self.typeLimitCombo.selectSet useBullets = self.bulletButton.isChecked() useTables = self.tableButton.isChecked() if (useBullets != currentFormat.useBullets or useTables != currentFormat.useTables): currentFormat.useBullets = useBullets currentFormat.useTables = useTables if useBullets: currentFormat.addBullets() elif useTables: currentFormat.addTables() else: currentFormat.clearBulletsAndTables() class FieldListPage(ConfigPage): """Config dialog page with an editable list of fields. """ def __init__(self, parent=None): """Initialize the config dialog page. Arguments: parent -- the parent overall dialog """ super().__init__(parent) topLayout = QVBoxLayout(self) typeBox = QGroupBox(_('&Data Type')) topLayout.addWidget(typeBox) typeLayout = QVBoxLayout(typeBox) self.typeCombo = QComboBox() typeLayout.addWidget(self.typeCombo) self.typeCombo.currentTextChanged.connect(self.changeCurrentType) fieldBox = QGroupBox(_('Modify &Field List')) topLayout.addWidget(fieldBox) horizLayout = QHBoxLayout(fieldBox) self.fieldListBox = QTreeWidget() horizLayout.addWidget(self.fieldListBox) self.fieldListBox.setRootIsDecorated(False) self.fieldListBox.setColumnCount(3) self.fieldListBox.setHeaderLabels([_('Name'), _('Type'), _('Sort Key')]) self.fieldListBox.currentItemChanged.connect(self.changeField) buttonLayout = QVBoxLayout() horizLayout.addLayout(buttonLayout) self.upButton = QPushButton(_('Move U&p')) buttonLayout.addWidget(self.upButton) self.upButton.clicked.connect(self.moveUp) self.downButton = QPushButton(_('Move Do&wn')) buttonLayout.addWidget(self.downButton) self.downButton.clicked.connect(self.moveDown) self.newButton = QPushButton(_('&New Field...')) buttonLayout.addWidget(self.newButton) self.newButton.clicked.connect(self.newField) self.renameButton = QPushButton(_('Rena&me Field...')) buttonLayout.addWidget(self.renameButton) self.renameButton.clicked.connect(self.renameField) self.deleteButton = QPushButton(_('Dele&te Field')) buttonLayout.addWidget(self.deleteButton) self.deleteButton.clicked.connect(self.deleteField) sortKeyButton = QPushButton(_('Sort &Keys...')) buttonLayout.addWidget(sortKeyButton) sortKeyButton.clicked.connect(self.defineSortKeys) def updateContent(self): """Update page contents from current format settings. """ typeNames = ConfigDialog.formatsRef.typeNames() self.typeCombo.blockSignals(True) self.typeCombo.clear() self.typeCombo.addItems(typeNames) self.typeCombo.setCurrentIndex(typeNames.index(ConfigDialog. currentTypeName)) self.typeCombo.blockSignals(False) currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] sortFields = [field for field in currentFormat.fields() if field.sortKeyNum > 0] sortFields.sort(key = operator.attrgetter('sortKeyNum')) if not sortFields: sortFields = [list(currentFormat.fields())[0]] self.fieldListBox.blockSignals(True) self.fieldListBox.clear() for field in currentFormat.fields(): try: sortKey = repr(sortFields.index(field) + 1) sortDir = _('fwd') if field.sortKeyForward else _('rev') sortKey = '{0} ({1})'.format(sortKey, sortDir) except ValueError: sortKey = '' typeName = fieldformat.translatedTypeName(field.typeName) QTreeWidgetItem(self.fieldListBox, [field.name, typeName, sortKey]) selectNum = currentFormat.fieldNames().index(ConfigDialog. currentFieldName) selectItem = self.fieldListBox.topLevelItem(selectNum) self.fieldListBox.setCurrentItem(selectItem) selectItem.setSelected(True) width = self.fieldListBox.viewport().width() self.fieldListBox.setColumnWidth(0, int(width // 2.5)) self.fieldListBox.setColumnWidth(1, int(width // 2.5)) self.fieldListBox.setColumnWidth(2, width // 5) self.fieldListBox.blockSignals(False) num = currentFormat.fieldNames().index(ConfigDialog.currentFieldName) self.upButton.setEnabled(num > 0 and not currentFormat.genericType) self.downButton.setEnabled(num < len(currentFormat.fieldDict) - 1 and not currentFormat.genericType) self.newButton.setEnabled(not currentFormat.genericType) self.renameButton.setEnabled(not currentFormat.genericType) self.deleteButton.setEnabled(len(currentFormat.fieldDict) > 1 and not currentFormat.genericType) def changeField(self, currentItem, prevItem): """Change the current format field based on a tree widget signal. Arguments: currentItem -- the new current tree widget item prevItem -- the old current tree widget item """ self.changeCurrentField(currentItem.text(0)) def moveUp(self): """Move field upward in the list based on button signal. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] fieldList = currentFormat.fieldNames() num = fieldList.index(ConfigDialog.currentFieldName) if num > 0: fieldList[num-1], fieldList[num] = fieldList[num], fieldList[num-1] currentFormat.reorderFields(fieldList) currentFormat.updateDerivedTypes() self.updateContent() self.mainDialogRef.setModified() def moveDown(self): """Move field downward in the list based on button signal. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] fieldList = currentFormat.fieldNames() num = fieldList.index(ConfigDialog.currentFieldName) if num < len(fieldList) - 1: fieldList[num], fieldList[num+1] = fieldList[num+1], fieldList[num] currentFormat.reorderFields(fieldList) currentFormat.updateDerivedTypes() self.updateContent() self.mainDialogRef.setModified() def newField(self): """Create and add a new field based on button signal. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] dlg = NameEntryDialog(_('Add Field'), _('Enter new field name:'), '', '', currentFormat.fieldNames(), self) if dlg.exec() == QDialog.DialogCode.Accepted: currentFormat.addField(dlg.text) ConfigDialog.currentFieldName = dlg.text currentFormat.updateDerivedTypes() self.updateContent() self.mainDialogRef.setModified() def renameField(self): """Prompt for new name and rename field based on button signal. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] fieldList = currentFormat.fieldNames() oldName = ConfigDialog.currentFieldName dlg = NameEntryDialog(_('Rename Field'), _('Rename from {} to:').format(oldName), oldName, '', fieldList, self) if dlg.exec() == QDialog.DialogCode.Accepted: num = fieldList.index(oldName) fieldList[num] = dlg.text for nodeFormat in [currentFormat] + currentFormat.derivedTypes: field = nodeFormat.fieldDict[oldName] field.name = dlg.text nodeFormat.fieldDict[field.name] = field nodeFormat.reorderFields(fieldList) if nodeFormat.conditional: nodeFormat.conditional.renameFields(oldName, field.name) # savedConditions = {} # for name, text in nodeFormat.savedConditionText.items(): # condition = conditional.Conditional(text, nodeFormat.name) # condition.renameFields(oldName, field.name) # savedConditions[name] = condition.conditionStr() # nodeFormat.savedConditionText = savedConditions renameDict = (ConfigDialog.formatsRef.fieldRenameDict. setdefault(nodeFormat.name, {})) # reverse rename dict - find original name (multiple renames) reverseDict = {} for old, new in renameDict.items(): reverseDict[new] = old origName = reverseDict.get(oldName, oldName) renameDict[origName] = dlg.text ConfigDialog.currentFieldName = dlg.text self.updateContent() self.mainDialogRef.setModified() def deleteField(self): """Delete field based on button signal. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] num = currentFormat.fieldNames().index(ConfigDialog.currentFieldName) for nodeFormat in [currentFormat] + currentFormat.derivedTypes: field = nodeFormat.fieldDict[ConfigDialog.currentFieldName] nodeFormat.removeField(field) del nodeFormat.fieldDict[ConfigDialog.currentFieldName] if num > 0: num -= 1 ConfigDialog.currentFieldName = currentFormat.fieldNames()[num] ConfigDialog.formatsRef.updateDerivedRefs() self.updateContent() self.mainDialogRef.setModified() def defineSortKeys(self): """Show a dialog to change sort key fields and directions. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] dlg = SortKeyDialog(currentFormat.fieldDict, self) if dlg.exec() == QDialog.DialogCode.Accepted: self.updateContent() self.mainDialogRef.setModified() _fileInfoFormatName = _('File Info Reference') class FieldConfigPage(ConfigPage): """Config dialog page to change parmaters of a field. """ def __init__(self, parent=None): """Initialize the config dialog page. Arguments: parent -- the parent overall dialog """ super().__init__(parent) self.currentFileInfoField = '' topLayout = QGridLayout(self) typeBox = QGroupBox(_('&Data Type')) topLayout.addWidget(typeBox, 0, 0) typeLayout = QVBoxLayout(typeBox) self.typeCombo = QComboBox() typeLayout.addWidget(self.typeCombo) self.typeCombo.currentTextChanged.connect(self.changeCurrentType) fieldBox = QGroupBox(_('F&ield')) topLayout.addWidget(fieldBox, 0, 1) fieldLayout = QVBoxLayout(fieldBox) self.fieldCombo = QComboBox() fieldLayout.addWidget(self.fieldCombo) self.fieldCombo.currentTextChanged.connect(self. changeCurrentField) fieldTypeBox = QGroupBox(_('&Field Type')) topLayout.addWidget(fieldTypeBox, 1, 0) fieldTypeLayout = QVBoxLayout(fieldTypeBox) self.fieldTypeCombo = QComboBox() fieldTypeLayout.addWidget(self.fieldTypeCombo) self.fieldTypeCombo.addItems(fieldformat.translatedFieldTypes) self.fieldTypeCombo.currentIndexChanged.connect(self.changeFieldType) self.formatBox = QGroupBox(_('Outpu&t Format')) topLayout.addWidget(self.formatBox, 1, 1) formatLayout = QHBoxLayout(self.formatBox) self.formatEdit = QLineEdit() formatLayout.addWidget(self.formatEdit) self.formatEdit.textEdited.connect(self.mainDialogRef.setModified) self.helpButton = QPushButton(_('Format &Help')) formatLayout.addWidget(self.helpButton) self.helpButton.clicked.connect(self.formatHelp) extraBox = QGroupBox(_('Extra Text')) topLayout.addWidget(extraBox, 2, 0, 2, 1) extraLayout = QVBoxLayout(extraBox) extraLayout.setSpacing(0) prefixLabel = QLabel(_('&Prefix')) extraLayout.addWidget(prefixLabel) self.prefixEdit = QLineEdit() extraLayout.addWidget(self.prefixEdit) prefixLabel.setBuddy(self.prefixEdit) self.prefixEdit.textEdited.connect(self.mainDialogRef.setModified) extraLayout.addSpacing(8) suffixLabel = QLabel(_('Suffi&x')) extraLayout.addWidget(suffixLabel) self.suffixEdit = QLineEdit() extraLayout.addWidget(self.suffixEdit) suffixLabel.setBuddy(self.suffixEdit) self.suffixEdit.textEdited.connect(self.mainDialogRef.setModified) defaultBox = QGroupBox(_('Default &Value for New Nodes')) topLayout.addWidget(defaultBox, 2, 1) defaultLayout = QVBoxLayout(defaultBox) self.defaultCombo = QComboBox() defaultLayout.addWidget(self.defaultCombo) self.defaultCombo.setEditable(True) self.defaultCombo.editTextChanged.connect(self.mainDialogRef. setModified) self.heightBox = QGroupBox(_('Editor Height')) topLayout.addWidget(self.heightBox, 3, 1) heightLayout = QHBoxLayout(self.heightBox) heightLabel = QLabel(_('Num&ber of text lines')) heightLayout.addWidget(heightLabel) self.heightCtrl = QSpinBox() heightLayout.addWidget(self.heightCtrl) self.heightCtrl.setMinimum(1) self.heightCtrl.setMaximum(999) heightLabel.setBuddy(self.heightCtrl) self.heightCtrl.valueChanged.connect(self.mainDialogRef.setModified) self.equationBox = QGroupBox(_('Math Equation')) topLayout.addWidget(self.equationBox, 4, 0, 1, 2) equationLayout = QHBoxLayout(self.equationBox) self.equationViewer = QLineEdit() equationLayout.addWidget(self.equationViewer) self.equationViewer.setReadOnly(True) equationButton = QPushButton(_('Define Equation')) equationLayout.addWidget(equationButton) equationButton.clicked.connect(self.defineMathEquation) htmlBox = QGroupBox(_('Output HTML')) topLayout.addWidget(htmlBox, 5, 0) htmlLayout = QVBoxLayout(htmlBox) self.htmlButton = QCheckBox(_('Evaluate &HTML tags')) htmlLayout.addWidget(self.htmlButton) self.htmlButton.toggled.connect(self.mainDialogRef.setModified) topLayout.setRowStretch(6, 1) def updateContent(self): """Update page contents from current format settings. """ typeNames = ConfigDialog.formatsRef.typeNames() self.typeCombo.blockSignals(True) self.typeCombo.clear() self.typeCombo.addItems(typeNames) self.typeCombo.addItem(_fileInfoFormatName) if self.currentFileInfoField: self.typeCombo.setCurrentIndex(len(typeNames)) else: self.typeCombo.setCurrentIndex(typeNames.index(ConfigDialog. currentTypeName)) self.typeCombo.blockSignals(False) currentFormat, currentField = self.currentFormatAndField() self.fieldCombo.blockSignals(True) self.fieldCombo.clear() self.fieldCombo.addItems(currentFormat.fieldNames()) selectNum = currentFormat.fieldNames().index(currentField.name) self.fieldCombo.setCurrentIndex(selectNum) self.fieldCombo.blockSignals(False) self.fieldTypeCombo.blockSignals(True) selectNum = fieldformat.fieldTypes.index(currentField.typeName) self.fieldTypeCombo.setCurrentIndex(selectNum) self.fieldTypeCombo.blockSignals(False) # also disable for generic types self.fieldTypeCombo.setEnabled(not self.currentFileInfoField) self.formatBox.setEnabled(currentField.defaultFormat != '') if (hasattr(currentField, 'resultType') and currentField.resultType == fieldformat.MathResult.text): self.formatBox.setEnabled(False) self.formatEdit.setText(currentField.format) self.prefixEdit.setText(currentField.prefix) self.suffixEdit.setText(currentField.suffix) self.defaultCombo.blockSignals(True) self.defaultCombo.clear() initDefault = currentField.getEditorInitDefault() self.defaultCombo.addItem(initDefault) initDefaultList = currentField.initDefaultChoices() if initDefaultList: if initDefaultList[0] == initDefault: initDefaultList[0] = '' # don't duplicate first entry self.defaultCombo.addItems(initDefaultList) self.defaultCombo.setCurrentIndex(0) self.defaultCombo.blockSignals(False) self.defaultCombo.setEnabled(currentField.supportsInitDefault and not self.currentFileInfoField) self.heightCtrl.blockSignals(True) self.heightCtrl.setValue(currentField.numLines) self.heightCtrl.blockSignals(False) self.heightBox.setEnabled(not self.currentFileInfoField and currentField.editorClassName in ('RichTextEditor', 'HtmlTextEditor', 'PlainTextEditor')) self.htmlButton.blockSignals(True) self.htmlButton.setChecked(currentField.evalHtml) self.htmlButton.blockSignals(False) self.htmlButton.setEnabled(not currentField.fixEvalHtmlSetting) if currentField.typeName == 'Math': self.equationBox.show() eqnText = currentField.equationText() self.equationViewer.setText(eqnText) else: self.equationBox.hide() def currentFormatAndField(self): """Return a tuple of the current format and field. Adjusts for a current file info field. """ if self.currentFileInfoField: currentFormat = ConfigDialog.formatsRef.fileInfoFormat fieldName = self.currentFileInfoField else: currentFormat = ConfigDialog.formatsRef[ConfigDialog. currentTypeName] fieldName = ConfigDialog.currentFieldName currentField = currentFormat.fieldDict[fieldName] return (currentFormat, currentField) def changeCurrentType(self, typeName): """Change the current format type based on a signal from lists. Arguments: typeName -- the name of the new current type """ self.readChanges() if typeName == _fileInfoFormatName: self.currentFileInfoField = (ConfigDialog.formatsRef. fileInfoFormat.fieldNames()[0]) else: ConfigDialog.currentTypeName = typeName ConfigDialog.currentFieldName = (ConfigDialog.formatsRef[typeName]. fieldNames()[0]) self.currentFileInfoField = '' self.updateContent() def changeCurrentField(self, fieldName): """Change the current format field based on a signal from lists. Arguments: fieldName -- the name of the new current field """ self.readChanges() if self.currentFileInfoField: self.currentFileInfoField = fieldName else: ConfigDialog.currentFieldName = fieldName self.updateContent() def changeFieldType(self): """Change the field type based on a combo box signal. """ self.readChanges() # preserve previous changes currentFormat, currentField = self.currentFormatAndField() selectNum = self.fieldTypeCombo.currentIndex() fieldTypeName = fieldformat.fieldTypes[selectNum] currentField.changeType(fieldTypeName) currentFormat.updateDerivedTypes() self.updateContent() self.mainDialogRef.setModified() def defineMathEquation(self): """Show the dialog to define an equation for a Math field. """ currentFormat, currentField = self.currentFormatAndField() prevEqnText = currentField.equationText() prevResultType = currentField.resultType dlg = MathEquationDialog(currentFormat, currentField, self) if (dlg.exec() == QDialog.DialogCode.Accepted and (currentField.equationText() != prevEqnText or currentField.resultType != prevResultType)): self.mainDialogRef.setModified() self.updateContent() def formatHelp(self): """Provide a format help menu based on a button signal. """ currentFormat, currentField = self.currentFormatAndField() menu = QMenu(self) self.formatHelpDict = {} for descript, key in currentField.getFormatHelpMenuList(): if descript: self.formatHelpDict[descript] = key menu.addAction(descript) else: menu.addSeparator() menu.popup(self.helpButton. mapToGlobal(QPoint(0, self.helpButton.height()))) menu.triggered.connect(self.insertFormat) def insertFormat(self, action): """Insert format text from help menu into edit box. Arguments: action -- the action from the help menu """ self.formatEdit.insert(self.formatHelpDict[action.text()]) def readChanges(self): """Make changes to the format for each widget. """ currentFormat, currentField = self.currentFormatAndField() if not currentField.fixEvalHtmlSetting: currentField.evalHtml = self.htmlButton.isChecked() prevFormat = currentField.format try: currentField.setFormat(self.formatEdit.text()) if (self.currentFileInfoField and self.formatEdit.text() != prevFormat): currentFormat.fieldFormatModified = True except ValueError: self.formatEdit.setText(currentField.format) currentField.prefix = self.prefixEdit.text() currentField.suffix = self.suffixEdit.text() if self.currentFileInfoField and (currentField.prefix or currentField.suffix): currentFormat.fieldFormatModified = True try: currentField.setInitDefault(self.defaultCombo.currentText()) except ValueError: self.defaultCombo.blockSignals(True) self.defaultCombo.setEditText(currentField.getEditorInitDefault()) self.defaultCombo.blockSignals(False) currentField.numLines = self.heightCtrl.value() _refLevelList = ['No Other Reference', 'File Info Reference', 'Any Ancestor Reference', 'Parent Reference', 'Grandparent Reference', 'Great Grandparent Reference', 'Child Reference', 'Child Count'] # _refLevelFlags correspond to _refLevelList _refLevelFlags = ['', '!', '?', '*', '**', '***', '&', '#'] fieldPattern = re.compile(r'{\*.*?\*}') class OutputPage(ConfigPage): """Config dialog page to define the node output strings. """ def __init__(self, parent=None): """Initialize the config dialog page. Arguments: parent -- the parent overall dialog """ super().__init__(parent) self.refLevelFlag = '' self.refLevelType = None topLayout = QGridLayout(self) typeBox = QGroupBox(_('&Data Type')) topLayout.addWidget(typeBox, 0, 0) typeLayout = QVBoxLayout(typeBox) self.typeCombo = QComboBox() typeLayout.addWidget(self.typeCombo) self.typeCombo.currentTextChanged.connect(self.changeCurrentType) fieldBox = QGroupBox(_('F&ield List')) topLayout.addWidget(fieldBox, 1, 0, 2, 1) boxLayout = QVBoxLayout(fieldBox) self.fieldListBox = QTreeWidget() boxLayout.addWidget(self.fieldListBox) self.fieldListBox.setRootIsDecorated(False) self.fieldListBox.setSelectionMode(QAbstractItemView.SelectionMode. ExtendedSelection) self.fieldListBox.setColumnCount(2) self.fieldListBox.setHeaderLabels([_('Name'), _('Type')]) self.fieldListBox.itemSelectionChanged.connect(self.changeField) titleButtonLayout = QVBoxLayout() topLayout.addLayout(titleButtonLayout, 1, 1) self.toTitleButton = QPushButton('>>') titleButtonLayout.addWidget(self.toTitleButton) self.toTitleButton.setMaximumWidth(self.toTitleButton. sizeHint().height()) self.toTitleButton.clicked.connect(self.fieldToTitle) self.delTitleButton = QPushButton('<<') titleButtonLayout.addWidget(self.delTitleButton) self.delTitleButton.setMaximumWidth(self.delTitleButton. sizeHint().height()) self.delTitleButton.clicked.connect(self.delTitleField) titleBox = QGroupBox(_('&Title Format')) topLayout.addWidget(titleBox, 1, 2) titleLayout = QVBoxLayout(titleBox) self.titleEdit = TitleEdit() titleLayout.addWidget(self.titleEdit) self.titleEdit.cursorPositionChanged.connect(self. setControlAvailability) self.titleEdit.textEdited.connect(self.mainDialogRef.setModified) outputButtonLayout = QVBoxLayout() topLayout.addLayout(outputButtonLayout, 2, 1) self.toOutputButton = QPushButton('>>') outputButtonLayout.addWidget(self.toOutputButton) self.toOutputButton.setMaximumWidth(self.toOutputButton. sizeHint().height()) self.toOutputButton.clicked.connect(self.fieldToOutput) self.delOutputButton = QPushButton('<<') outputButtonLayout.addWidget(self.delOutputButton) self.delOutputButton.setMaximumWidth(self.delOutputButton. sizeHint().height()) self.delOutputButton.clicked.connect(self.delOutputField) outputBox = QGroupBox(_('Out&put Format')) topLayout.addWidget(outputBox, 2, 2) outputLayout = QVBoxLayout(outputBox) self.outputEdit = QTextEdit() self.outputEdit.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) outputLayout.addWidget(self.outputEdit) self.outputEdit.setTabChangesFocus(True) self.outputEdit.cursorPositionChanged.connect(self. setControlAvailability) self.outputEdit.textChanged.connect(self.mainDialogRef.setModified) # advanced widgets otherBox = QGroupBox(_('Other Field References')) topLayout.addWidget(otherBox, 0, 2) self.advancedWidgets.append(otherBox) otherLayout = QHBoxLayout(otherBox) levelLayout = QVBoxLayout() otherLayout.addLayout(levelLayout) levelLayout.setSpacing(0) levelLabel = QLabel(_('Reference Le&vel')) levelLayout.addWidget(levelLabel) levelCombo = QComboBox() levelLayout.addWidget(levelCombo) levelLabel.setBuddy(levelCombo) levelCombo.addItems(_refLevelList) levelCombo.currentIndexChanged.connect(self.changeRefLevel) refTypeLayout = QVBoxLayout() otherLayout.addLayout(refTypeLayout) refTypeLayout.setSpacing(0) refTypeLabel = QLabel(_('Refere&nce Type')) refTypeLayout.addWidget(refTypeLabel) self.refTypeCombo = QComboBox() refTypeLayout.addWidget(self.refTypeCombo) refTypeLabel.setBuddy(self.refTypeCombo) self.refTypeCombo.currentIndexChanged.connect(self.changeRefType) topLayout.setRowStretch(1, 1) topLayout.setRowStretch(2, 1) def updateContent(self): """Update page contents from current format settings. """ typeNames = ConfigDialog.formatsRef.typeNames() self.typeCombo.blockSignals(True) self.typeCombo.clear() self.typeCombo.addItems(typeNames) self.typeCombo.setCurrentIndex(typeNames.index(ConfigDialog. currentTypeName)) self.typeCombo.blockSignals(False) currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] self.updateFieldList() self.titleEdit.blockSignals(True) self.titleEdit.setText(currentFormat.getTitleLine()) self.titleEdit.end(False) self.titleEdit.blockSignals(False) self.outputEdit.blockSignals(True) self.outputEdit.setPlainText('\n'.join(currentFormat.getOutputLines())) cursor = self.outputEdit.textCursor() cursor.movePosition(QTextCursor.MoveOperation.End) self.outputEdit.setTextCursor(cursor) self.outputEdit.blockSignals(False) self.refTypeCombo.blockSignals(True) self.refTypeCombo.clear() self.refTypeCombo.addItems(typeNames) refLevelType = (self.refLevelType if self.refLevelType else ConfigDialog.currentTypeName) try: self.refTypeCombo.setCurrentIndex(typeNames.index(refLevelType)) except ValueError: # type no longer exists self.refLevelType = ConfigDialog.currentTypeName self.refTypeCombo.setCurrentIndex(typeNames.index(self. refLevelType)) self.refTypeCombo.blockSignals(False) self.setControlAvailability() def updateFieldList(self): """Reload the field list box. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] if not self.refLevelFlag: activeFormat = currentFormat elif self.refLevelFlag == '!': activeFormat = ConfigDialog.formatsRef.fileInfoFormat elif self.refLevelFlag == '#': activeFormat = nodeformat.DescendantCountFormat() else: try: activeFormat = ConfigDialog.formatsRef[self.refLevelType] except (KeyError, ValueError): self.refLevelType = ConfigDialog.currentTypeName activeFormat = currentFormat self.fieldListBox.blockSignals(True) self.fieldListBox.clear() for field in activeFormat.fields(): if field.showInDialog: typeName = fieldformat.translatedTypeName(field.typeName) QTreeWidgetItem(self.fieldListBox, [field.name, typeName]) selectList = self.fieldListBox.findItems(ConfigDialog.currentFieldName, Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchCaseSensitive) selectItem = (selectList[0] if selectList else self.fieldListBox.topLevelItem(0)) self.fieldListBox.setCurrentItem(selectItem) selectItem.setSelected(True) self.fieldListBox.setColumnWidth(0, self.fieldListBox.width() // 2) self.fieldListBox.blockSignals(False) def changeField(self): """Change the current format field based on a tree widget signal. Not set if a special field ref level is active. """ selectList = self.fieldListBox.selectedItems() if (not self.refLevelFlag and len(selectList) == 1): ConfigDialog.currentFieldName = selectList[0].text(0) self.setControlAvailability() def setControlAvailability(self): """Set controls available based on text cursor movements. """ fieldsSelected = len(self.fieldListBox.selectedItems()) > 0 cursorInTitleField = self.isCursorInTitleField() self.toTitleButton.setEnabled(cursorInTitleField == None and fieldsSelected) self.delTitleButton.setEnabled(cursorInTitleField == True) cursorInOutputField = self.isCursorInOutputField() self.toOutputButton.setEnabled(cursorInOutputField == None and fieldsSelected) self.delOutputButton.setEnabled(cursorInOutputField == True) self.refTypeCombo.setEnabled(self.refLevelFlag not in ('', '!', '#')) def fieldToTitle(self): """Add selected field to cursor pos in title editor. """ self.titleEdit.insert(self.selectedFieldSepNames(' ')) self.titleEdit.setFocus() def delTitleField(self): """Remove field from cursor pos in title editor. """ if self.isCursorInTitleField(True): self.titleEdit.insert('') def fieldToOutput(self): """Add selected field to cursor pos in output editor. """ self.outputEdit.insertPlainText(self.selectedFieldSepNames()) self.outputEdit.setFocus() def delOutputField(self): """Remove field from cursor pos in output editor. """ if self.isCursorInOutputField(True): self.outputEdit.insertPlainText('') def selectedFieldSepNames(self, sep='\n'): """Return selected field name(s) with proper separators. Adjusts for special field ref levels. Multiple selections result in fields joined with the separator. Arguments: sep -- the separator to join multiple fields. """ fields = ['{{*{0}{1}*}}'.format(self.refLevelFlag, item.text(0)) for item in self.fieldListBox.selectedItems()] return '\n'.join(fields) def isCursorInTitleField(self, selectField=False): """Return True if a field pattern encloses the cursor/selection. Return False if the selection overlaps a field. Return None if there is no field at the cursor. Arguments: selectField -- select the entire field pattern if True. """ cursorPos = self.titleEdit.cursorPosition() selectStart = self.titleEdit.selectionStart() if selectStart < 0: selectStart = cursorPos elif selectStart == cursorPos: # backward selection cursorPos += len(self.titleEdit.selectedText()) fieldPos = self.fieldPosAtCursor(selectStart, cursorPos, self.titleEdit.text()) if not fieldPos: return None start, end = fieldPos if start == None or end == None: return False if selectField: self.titleEdit.setSelection(start, end - start) return True def isCursorInOutputField(self, selectField=False): """Return True if a field pattern encloses the cursor/selection. Return False if the selection overlaps a field. Return None if there is no field at the cursor. Arguments: selectField -- select the entire field pattern if True. """ outputCursor = self.outputEdit.textCursor() selectStart = outputCursor.anchor() cursorPos = outputCursor.position() block = outputCursor.block() blockStart = block.position() if selectStart < blockStart or (selectStart > blockStart + block.length()): return False # multi-line selection fieldPos = self.fieldPosAtCursor(selectStart - blockStart, cursorPos - blockStart, block.text()) if not fieldPos: return None start, end = fieldPos if start == None or end == None: return False if selectField: outputCursor.setPosition(start + blockStart) outputCursor.setPosition(end + blockStart, QTextCursor.MoveMode.KeepAnchor) self.outputEdit.setTextCursor(outputCursor) return True def fieldPosAtCursor(self, anchorPos, cursorPos, textLine): """Find the position of the field pattern that encloses the selection. Return a tuple of (start, end) positions of the field if found. Return (start, None) or (None, end) if the selection overlaps. Return None if no field is found. Arguments: anchorPos -- the selection start cursorPos -- the selection end textLine -- the text to search """ for match in fieldPattern.finditer(textLine): start = (match.start() if match.start() < anchorPos < match.end() else None) end = (match.end() if match.start() < cursorPos < match.end() else None) if start != None or end != None: return (start, end) return None def changeRefLevel(self, num): """Change other field ref level based on a combobox signal. Arguments: num -- the combobox index selected """ self.refLevelFlag = _refLevelFlags[num] if self.refLevelFlag in ('', '!', '#'): self.refLevelType = None elif not self.refLevelType: self.refLevelType = ConfigDialog.currentTypeName self.updateFieldList() self.setControlAvailability() def changeRefType(self, num): """Change the other field ref level type based on a combobox signal. Arguments: num -- the combobox index selected """ self.refLevelType = ConfigDialog.formatsRef.typeNames()[num] self.updateFieldList() self.setControlAvailability() def readChanges(self): """Make changes to the format for each widget. """ currentFormat = ConfigDialog.formatsRef[ConfigDialog.currentTypeName] currentFormat.changeTitleLine(self.titleEdit.text()) currentFormat.changeOutputLines(self.outputEdit.toPlainText().strip(). split('\n'), not currentFormat.formatHtml) class TitleEdit(QLineEdit): """LineEdit that avoids changing the selection on focus changes. """ focusIn = pyqtSignal(QWidget) def __init__(self, parent=None): """Initialize the config dialog page. Arguments: parent -- the parent dialog """ super().__init__(parent) def focusInEvent(self, event): """Override to keep selection & cursor position. Arguments: event -- the focus event """ cursorPos = self.cursorPosition() selectStart = self.selectionStart() if selectStart == cursorPos: selectStart = cursorPos + len(self.selectedText()) super().focusInEvent(event) self.setCursorPosition(cursorPos) if selectStart >= 0: self.setSelection(selectStart, cursorPos - selectStart) self.focusIn.emit(self) def focusOutEvent(self, event): """Override to keep selection & cursor position. Arguments: event -- the focus event """ cursorPos = self.cursorPosition() selectStart = self.selectionStart() if selectStart == cursorPos: selectStart = cursorPos + len(self.selectedText()) super().focusOutEvent(event) self.setCursorPosition(cursorPos) if selectStart >= 0: self.setSelection(selectStart, cursorPos - selectStart) class TypeLimitCombo(QComboBox): """A combo box for selecting limited child types. """ limitChanged = pyqtSignal() def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.checkBoxDialog = None self.typeNames = [] self.selectSet = set() def updateLists(self, typeNames, selectSet): """Update control text and store data for popup. Arguments: typeNames -- a list of available type names selectSet -- a set of seleected type names """ self.typeNames = typeNames self.updateSelects(selectSet) def updateSelects(self, selectSet): """Update control text and store selected items. Arguments: selectSet -- a set of seleected type names """ self.selectSet = selectSet if not selectSet or selectSet == set(self.typeNames): text = _('[All Types Available]') self.selectSet = set() else: text = ', '.join(sorted(selectSet)) self.addItem(text) self.setCurrentText(text) def showPopup(self): """Override to show a popup entry widget in place of a list view. """ self.checkBoxDialog = TypeLimitCheckBox(self.typeNames, self.selectSet, self) self.checkBoxDialog.setMinimumWidth(self.width()) self.checkBoxDialog.buttonChanged.connect(self.updateFromButton) self.checkBoxDialog.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.checkBoxDialog.width() + 1) screenBottom = (QApplication.primaryScreen().availableGeometry(). bottom()) if pos.y() + self.checkBoxDialog.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.checkBoxDialog.height()) self.checkBoxDialog.move(pos) def hidePopup(self): """Override to hide the popup entry widget. """ if self.checkBoxDialog: self.checkBoxDialog.hide() super().hidePopup() def updateFromButton(self): """Update selected items based on a button change. """ self.updateSelects(self.checkBoxDialog.selectSet()) self.limitChanged.emit() class TypeLimitCheckBox(QDialog): """A popup dialog box for selecting limited child types. """ buttonChanged = pyqtSignal() def __init__(self, textList, selectSet, parent=None): """Initialize the combination dialog. Arguments: textList -- a list of text choices selectSet -- a set of choices to preselect parent -- the parent, if given """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Popup) topLayout = QVBoxLayout(self) topLayout.setContentsMargins(0, 0, 0, 0) scrollArea = QScrollArea() scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) topLayout.addWidget(scrollArea) innerWidget = QWidget() innerLayout = QVBoxLayout(innerWidget) self.buttonGroup = QButtonGroup(self) self.buttonGroup.setExclusive(False) self.buttonGroup.buttonClicked.connect(self.buttonChanged) for text in textList: button = QCheckBox(text, innerWidget) if text in selectSet: button.setChecked(True) self.buttonGroup.addButton(button) innerLayout.addWidget(button) scrollArea.setWidget(innerWidget) buttons = self.buttonGroup.buttons() if buttons: buttons[0].setFocus() def selectSet(self): """Return a set of currently checked text. """ result = set() for button in self.buttonGroup.buttons(): if button.isChecked(): result.add(button.text()) return result def selectAll(self): """Select all of the entries. """ for button in self.buttonGroup.buttons(): button.setChecked(True) def selectNone(self): """Clear all of the selections. """ for button in self.buttonGroup.buttons(): button.setChecked(False) def contextMenuEvent(self, event): """Create a popup context menu. Arguments: event -- the menu even to process """ menu = QMenu(self) menu.addAction(_('&Select All'), self.selectAll) menu.addAction(_('Select &None'), self.selectNone) menu.exec(event.globalPos()) _illegalRe = re.compile(r'[^\w_\-.]') class NameEntryDialog(QDialog): """Dialog to handle user entry of a type or field name. Restricts entry to alpha-numerics, underscores, dashes and periods. """ def __init__(self, caption, labelText, defaultText='', addCheckBox = '', badText=None, parent=None): """Initialize the name entry class. Arguments: caption -- the window title labelText -- text for a descriptive lable defaultText -- initial text addCheckBox -- the label for an extra check box if needed badText -- a set or list of other illegal strings parent -- the parent overall dialog """ super().__init__(parent) self.badText = set() if badText: self.badText = badText self.text = '' self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(caption) topLayout = QVBoxLayout(self) label = QLabel(labelText) topLayout.addWidget(label) self.entry = QLineEdit(defaultText) topLayout.addWidget(self.entry) self.entry.setFocus() self.entry.returnPressed.connect(self.accept) self.extraChecked = False if addCheckBox: self.extraCheckBox = QCheckBox(addCheckBox) topLayout.addWidget(self.extraCheckBox) else: self.extraCheckBox = None ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) def accept(self): """Check for acceptable string before closing. """ self.text = self.entry.text().strip() if not self.text: error = _('The name cannot be empty') elif not self.text[0].isalpha(): error = _('The name must start with a letter') elif self.text[:3].lower() == 'xml': error = _('The name cannot start with "xml"') elif ' ' in self.text: error = _('The name cannot contain spaces') elif _illegalRe.search(self.text): badChars = set(_illegalRe.findall(self.text)) error = (_('The following characters are not allowed: {}'). format(''.join(badChars))) elif self.text in self.badText: error = _('The name was already used') else: if self.extraCheckBox: self.extraChecked = self.extraCheckBox.isChecked() return super().accept() QMessageBox.warning(self, 'TreeLine', error) class IconSelectDialog(QDialog): """Dialog for selecting icons for a format type. """ dialogSize = () dialogPos = () def __init__(self, nodeFormat, parent=None): """Create the icon select dialog. Arguments: nodeFormat -- the current node format to be set parent -- the parent overall dialog """ super().__init__(parent) self.currentIconName = nodeFormat.iconName if (not self.currentIconName or self.currentIconName not in globalref.treeIcons): self.currentIconName = icondict.defaultName self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Set Data Type Icon')) topLayout = QVBoxLayout(self) self.iconView = QListWidget() self.iconView.setViewMode(QListView.ViewMode.ListMode) self.iconView.setMovement(QListView.Movement.Static) self.iconView.setWrapping(True) self.iconView.setGridSize(QSize(112, 32)) topLayout.addWidget(self.iconView) self.iconView.itemDoubleClicked.connect(self.accept) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() clearButton = QPushButton(_('Clear &Select')) ctrlLayout.addWidget(clearButton) clearButton.clicked.connect(self.iconView.clearSelection) okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) if IconSelectDialog.dialogSize: self.resize(IconSelectDialog.dialogSize[0], IconSelectDialog.dialogSize[1]) self.move(IconSelectDialog.dialogPos[0], IconSelectDialog.dialogPos[1]) self.loadIcons() def loadIcons(self): """Load icons from the icon dict source. """ if not globalref.treeIcons.allLoaded: globalref.treeIcons.loadAllIcons() for name, icon in globalref.treeIcons.items(): if icon: item = QListWidgetItem(icon, name, self.iconView) if name == self.currentIconName: self.iconView.setCurrentItem(item) self.iconView.sortItems() selectedItem = self.iconView.currentItem() if selectedItem: self.iconView.scrollToItem(selectedItem, QAbstractItemView.ScrollHint. PositionAtCenter) def saveSize(self): """Record dialog size at close. """ IconSelectDialog.dialogSize = (self.width(), self.height()) IconSelectDialog.dialogPos = (self.x(), self.y()) def accept(self): """Save changes before closing. """ selectedItems = self.iconView.selectedItems() if selectedItems: self.currentIconName = selectedItems[0].text() if self.currentIconName == icondict.defaultName: self.currentIconName = '' else: self.currentIconName = icondict.noneName self.saveSize() super().accept() def reject(self): """Save dialog size before closing. """ self.saveSize() super().reject() class SortKeyDialog(QDialog): """Dialog for defining sort key fields and directions. """ directionNameDict = {True: _('forward'), False: _('reverse')} directionVarDict = dict([(name, boolVal) for boolVal, name in directionNameDict.items()]) def __init__(self, fieldDict, parent=None): """Create the sort key dialog. Arguments: fieldDict -- a dict of field names and values parent -- the parent overall dialog """ super().__init__(parent) self.fieldDict = fieldDict self.numChanges = 0 self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Sort Key Fields')) topLayout = QVBoxLayout(self) horizLayout = QHBoxLayout() topLayout.addLayout(horizLayout) fieldBox = QGroupBox(_('Available &Fields')) horizLayout.addWidget(fieldBox) boxLayout = QVBoxLayout(fieldBox) self.fieldListBox = QTreeWidget() boxLayout.addWidget(self.fieldListBox) self.fieldListBox.setRootIsDecorated(False) self.fieldListBox.setColumnCount(2) self.fieldListBox.setHeaderLabels([_('Name'), _('Type')]) midButtonLayout = QVBoxLayout() horizLayout.addLayout(midButtonLayout) self.addFieldButton = QPushButton('>>') midButtonLayout.addWidget(self.addFieldButton) self.addFieldButton.setMaximumWidth(self.addFieldButton. sizeHint().height()) self.addFieldButton.clicked.connect(self.addField) self.removeFieldButton = QPushButton('<<') midButtonLayout.addWidget(self.removeFieldButton) self.removeFieldButton.setMaximumWidth(self.removeFieldButton. sizeHint().height()) self.removeFieldButton.clicked.connect(self.removeField) sortBox = QGroupBox(_('&Sort Criteria')) horizLayout.addWidget(sortBox) boxLayout = QVBoxLayout(sortBox) self.sortListBox = QTreeWidget() boxLayout.addWidget(self.sortListBox) self.sortListBox.setRootIsDecorated(False) self.sortListBox.setColumnCount(3) self.sortListBox.setHeaderLabels(['#', _('Field'), _('Direction')]) self.sortListBox.currentItemChanged.connect(self.setControlsAvail) rightButtonLayout = QVBoxLayout() horizLayout.addLayout(rightButtonLayout) self.upButton = QPushButton(_('Move &Up')) rightButtonLayout.addWidget(self.upButton) self.upButton.clicked.connect(self.moveUp) self.downButton = QPushButton(_('&Move Down')) rightButtonLayout.addWidget(self.downButton) self.downButton.clicked.connect(self.moveDown) self.flipButton = QPushButton(_('Flip &Direction')) rightButtonLayout.addWidget(self.flipButton) self.flipButton.clicked.connect(self.flipDirection) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() self.okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(self.okButton) self.okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.updateContent() def updateContent(self): """Update dialog contents from current format settings. """ sortFields = [field for field in self.fieldDict.values() if field.sortKeyNum > 0] sortFields.sort(key = operator.attrgetter('sortKeyNum')) if not sortFields: sortFields = [list(self.fieldDict.values())[0]] self.fieldListBox.clear() for field in self.fieldDict.values(): if field not in sortFields: QTreeWidgetItem(self.fieldListBox, [field.name, field.typeName]) if self.fieldListBox.topLevelItemCount() > 0: self.fieldListBox.setCurrentItem(self.fieldListBox.topLevelItem(0)) self.fieldListBox.setColumnWidth(0, self.fieldListBox.sizeHint(). width() // 2) self.sortListBox.blockSignals(True) self.sortListBox.clear() for num, field in enumerate(sortFields, 1): sortDir = SortKeyDialog.directionNameDict[field.sortKeyForward] QTreeWidgetItem(self.sortListBox, [repr(num), field.name, sortDir]) self.sortListBox.setCurrentItem(self.sortListBox.topLevelItem(0)) self.sortListBox.blockSignals(False) self.sortListBox.setColumnWidth(0, self.sortListBox.sizeHint(). width() // 8) self.setControlsAvail() def setControlsAvail(self): """Set controls available based on selections. """ self.addFieldButton.setEnabled(self.fieldListBox.topLevelItemCount() > 0) hasSortItems = self.sortListBox.topLevelItemCount() > 0 self.removeFieldButton.setEnabled(hasSortItems) if hasSortItems: sortPosNum = self.sortListBox.indexOfTopLevelItem(self.sortListBox. currentItem()) self.upButton.setEnabled(hasSortItems and sortPosNum > 0) self.downButton.setEnabled(hasSortItems and sortPosNum < self.sortListBox.topLevelItemCount() - 1) self.flipButton.setEnabled(hasSortItems) self.okButton.setEnabled(hasSortItems) def addField(self): """Add a field to the sort criteria list. """ itemNum = self.fieldListBox.indexOfTopLevelItem(self.fieldListBox. currentItem()) fieldName = self.fieldListBox.takeTopLevelItem(itemNum).text(0) field = self.fieldDict[fieldName] sortNum = self.sortListBox.topLevelItemCount() + 1 sortDir = SortKeyDialog.directionNameDict[field.sortKeyForward] self.sortListBox.blockSignals(True) sortItem = QTreeWidgetItem(self.sortListBox, [repr(sortNum), fieldName, sortDir]) self.sortListBox.setCurrentItem(sortItem) self.sortListBox.blockSignals(False) self.setControlsAvail() self.numChanges += 1 def removeField(self): """Remove a field from the sort criteria list. """ itemNum = self.sortListBox.indexOfTopLevelItem(self.sortListBox. currentItem()) self.sortListBox.blockSignals(True) fieldName = self.sortListBox.takeTopLevelItem(itemNum).text(1) self.renumberSortFields() self.sortListBox.blockSignals(False) field = self.fieldDict[fieldName] sortFieldNames = set() for num in range(self.sortListBox.topLevelItemCount()): sortFieldNames.add(self.sortListBox.topLevelItem(num).text(1)) fieldList = [field for field in self.fieldDict.values() if field.name not in sortFieldNames] pos = fieldList.index(field) fieldItem = QTreeWidgetItem([fieldName, field.typeName]) self.fieldListBox.insertTopLevelItem(pos, fieldItem) self.setControlsAvail() self.numChanges += 1 def moveUp(self): """Move a field upward in the sort criteria. """ itemNum = self.sortListBox.indexOfTopLevelItem(self.sortListBox. currentItem()) self.sortListBox.blockSignals(True) sortItem = self.sortListBox.takeTopLevelItem(itemNum) self.sortListBox.insertTopLevelItem(itemNum - 1, sortItem) self.sortListBox.setCurrentItem(sortItem) self.renumberSortFields() self.sortListBox.blockSignals(False) self.setControlsAvail() self.numChanges += 1 def moveDown(self): """Move a field downward in the sort criteria. """ itemNum = self.sortListBox.indexOfTopLevelItem(self.sortListBox. currentItem()) self.sortListBox.blockSignals(True) sortItem = self.sortListBox.takeTopLevelItem(itemNum) self.sortListBox.insertTopLevelItem(itemNum + 1, sortItem) self.sortListBox.setCurrentItem(sortItem) self.renumberSortFields() self.sortListBox.blockSignals(False) self.setControlsAvail() self.numChanges += 1 def flipDirection(self): """Toggle the direction of the current sort field. """ sortItem = self.sortListBox.currentItem() oldDirection = SortKeyDialog.directionVarDict[sortItem.text(2)] newDirection = SortKeyDialog.directionNameDict[not oldDirection] sortItem.setText(2, newDirection) self.numChanges += 1 def renumberSortFields(self): """Update field numbers in the sort list. """ for num in range(self.sortListBox.topLevelItemCount()): self.sortListBox.topLevelItem(num).setText(0, repr(num + 1)) def accept(self): """Save changes before closing. """ if not self.numChanges: return self.reject() for field in self.fieldDict.values(): field.sortKeyNum = 0 field.sortKeyForward = True for num in range(self.sortListBox.topLevelItemCount()): fieldItem = self.sortListBox.topLevelItem(num) field = self.fieldDict[fieldItem.text(1)] field.sortKeyNum = num + 1 field.sortKeyForward = SortKeyDialog.directionVarDict[fieldItem. text(2)] return super().accept() _mathRefLevels = [_('Self Reference'), _('Parent Reference'), _('Root Reference'), _('Child Reference'), _('Child Count')] # _mathRefLevelFlags correspond to _mathRefLevels _mathRefLevelFlags = ['', '*', '$', '&', '#'] _mathResultTypes = [N_('Number Result'), N_('Date Result'), N_('Time Result'), N_('Boolean Result'), N_('Text Result')] _operatorTypes = [_('Arithmetic Operators'), _('Comparison Operators'), _('Text Operators')] _arithmeticOperators = [('+', _('add')), ('-', _('subtract')), ('*', _('multiply')), ('/', _('divide')), ('//', _('floor divide')), ('%', _('modulus')), ('**', _('power')), ('sum()', _('sum of items')), ('max()', _('maximum')), ('min()', _('minimum')), ('mean()', _('average')), ('abs()', _('absolute value')), ('sqrt()', _('square root')), ('log()', _('natural logarithm')), ('log10()', _('base-10 logarithm')), ('factorial()', _('factorial')), ('round()', _('round to num digits')), ('floor()', _('lower integer')), ('ceil()', _('higher integer')), ('int()', _('truncated integer')), ('float()', _('floating point')), ('sin()', _('sine of radians')), ('cos()', _('cosine of radians')), ('tan()', _('tangent of radians')), ('asin()', _('arc sine')), ('acos()', _('arc cosine')), ('atan()', _('arc tangent')), ('degrees()', _('radians to degrees')), ('radians()', _('degrees to radians')), ('pi', _('pi constant')), ('e', _('natural log constant')), ('count()', _('number of words in arg'))] _comparisonOperators = [('==', _('equal to')), ('<', _('less than')), ('>', _('greater than')), ('<=', _('less than or equal to')), ('>=', _('greater than or equal to')), ('!=', _('not equal to')), ('() if () else ()', _('true value, condition, false value')), ('and', _('logical and')), ('or', _('logical or')), ('startswith()', _('true if 1st text arg starts with 2nd arg')), ('endswith()', _('true if 1st text arg ends with 2nd arg')), ('contains()', _('true if 1st text arg contains 2nd arg'))] _textOperators = [('+', _('concatenate text')), ("join(' ', )", _('join text using 1st arg as separator')), ('upper()', _('convert text to upper case')), ('lower()', _('convert text to lower case')), ('replace()', _('in 1st arg, replace 2nd arg with 3rd arg'))] # _operatorLists correspond to _operatorTypes _operatorLists = [_arithmeticOperators, _comparisonOperators, _textOperators] class MathEquationDialog(QDialog): """Dialog for defining equations for Math fields. """ def __init__(self, nodeFormat, field, parent=None): """Create the math equation dialog. Arguments: nodeFormat -- the current node format field -- the Math field """ super().__init__(parent) self.nodeFormat = nodeFormat self.typeFormats = self.nodeFormat.parentFormats self.field = field self.refLevelFlag = '' self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Define Math Field Equation')) topLayout = QGridLayout(self) fieldBox = QGroupBox(_('Field References')) topLayout.addWidget(fieldBox, 0, 0, 2, 1) fieldLayout = QVBoxLayout(fieldBox) innerLayout = QVBoxLayout() innerLayout.setSpacing(0) fieldLayout.addLayout(innerLayout) levelLabel = QLabel(_('Reference &Level')) innerLayout.addWidget(levelLabel) levelCombo = QComboBox() innerLayout.addWidget(levelCombo) levelLabel.setBuddy(levelCombo) levelCombo.addItems(_mathRefLevels) levelCombo.currentIndexChanged.connect(self.changeRefLevel) innerLayout = QVBoxLayout() innerLayout.setSpacing(0) fieldLayout.addLayout(innerLayout) typeLabel = QLabel(_('Reference &Type')) innerLayout.addWidget(typeLabel) self.typeCombo = QComboBox() innerLayout.addWidget(self.typeCombo) typeLabel.setBuddy(self.typeCombo) self.typeCombo.addItems(self.typeFormats.typeNames()) self.typeCombo.currentIndexChanged.connect(self.updateFieldList) innerLayout = QVBoxLayout() innerLayout.setSpacing(0) fieldLayout.addLayout(innerLayout) fieldLabel = QLabel(_('Available &Field List')) innerLayout.addWidget(fieldLabel) self.fieldListBox = QTreeWidget() innerLayout.addWidget(self.fieldListBox) fieldLabel.setBuddy(self.fieldListBox) self.fieldListBox.setRootIsDecorated(False) self.fieldListBox.setColumnCount(2) self.fieldListBox.setHeaderLabels([_('Name'), _('Type')]) resultTypeBox = QGroupBox(_('&Result Type')) topLayout.addWidget(resultTypeBox, 0, 1) resultTypeLayout = QVBoxLayout(resultTypeBox) self.resultTypeCombo = QComboBox() resultTypeLayout.addWidget(self.resultTypeCombo) self.resultTypeCombo.addItems([_(str) for str in _mathResultTypes]) results = [s.split(' ', 1)[0].lower() for s in _mathResultTypes] resultStr = self.field.resultType.name self.resultTypeCombo.setCurrentIndex(results.index(resultStr)) operBox = QGroupBox(_('Operations')) topLayout.addWidget(operBox, 1, 1) operLayout = QVBoxLayout(operBox) innerLayout = QVBoxLayout() innerLayout.setSpacing(0) operLayout.addLayout(innerLayout) operTypeLabel = QLabel(_('O&perator Type')) innerLayout.addWidget(operTypeLabel) operTypeCombo = QComboBox() innerLayout.addWidget(operTypeCombo) operTypeLabel.setBuddy(operTypeCombo) operTypeCombo.addItems(_operatorTypes) operTypeCombo.currentIndexChanged.connect(self.replaceOperatorList) innerLayout = QVBoxLayout() innerLayout.setSpacing(0) operLayout.addLayout(innerLayout) operListLabel = QLabel(_('Oper&ator List')) innerLayout.addWidget(operListLabel) self.operListBox = QTreeWidget() innerLayout.addWidget(self.operListBox) operListLabel.setBuddy(self.operListBox) self.operListBox.setRootIsDecorated(False) self.operListBox.setColumnCount(2) self.operListBox.setHeaderLabels([_('Name'), _('Description')]) self.replaceOperatorList(0) buttonLayout = QHBoxLayout() topLayout.addLayout(buttonLayout, 2, 0) buttonLayout.addStretch() self.addFieldButton = QPushButton('\u25bc') buttonLayout.addWidget(self.addFieldButton) self.addFieldButton.setMaximumWidth(self.addFieldButton. sizeHint().height()) self.addFieldButton.clicked.connect(self.addField) self.delFieldButton = QPushButton('\u25b2') buttonLayout.addWidget(self.delFieldButton) self.delFieldButton.setMaximumWidth(self.delFieldButton. sizeHint().height()) self.delFieldButton.clicked.connect(self.deleteField) buttonLayout.addStretch() buttonLayout = QHBoxLayout() topLayout.addLayout(buttonLayout, 2, 1) self.addOperButton = QPushButton('\u25bc') buttonLayout.addWidget(self.addOperButton) self.addOperButton.setMaximumWidth(self.addOperButton. sizeHint().height()) self.addOperButton.clicked.connect(self.addOperator) equationBox = QGroupBox(_('&Equation')) topLayout.addWidget(equationBox, 3, 0, 1, 2) equationLayout = QVBoxLayout(equationBox) self.equationEdit = TitleEdit() equationLayout.addWidget(self.equationEdit) self.equationEdit.setText(self.field.equationText()) self.equationEdit.cursorPositionChanged.connect(self. setControlAvailability) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout, 4, 0, 1, 2) ctrlLayout.addStretch() okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.setDefault(True) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.changeRefLevel(0) self.equationEdit.setFocus() def updateFieldList(self): """Update field list based on reference type setting. """ currentFormat = self.typeFormats[self.typeCombo.currentText()] self.fieldListBox.clear() if self.refLevelFlag != '#': for field in currentFormat.fields(): if (hasattr(field, 'mathValue') and field.showInDialog and (self.refLevelFlag or field != self.field)): QTreeWidgetItem(self.fieldListBox, [field.name, _(field.typeName)]) else: QTreeWidgetItem(self.fieldListBox, [_('Count'), _('Number of Children')]) if self.fieldListBox.topLevelItemCount(): selectItem = self.fieldListBox.topLevelItem(0) self.fieldListBox.setCurrentItem(selectItem) selectItem.setSelected(True) self.fieldListBox.resizeColumnToContents(0) self.fieldListBox.setColumnWidth(0, self.fieldListBox.columnWidth(0) * 2) self.setControlAvailability() def setControlAvailability(self): """Set controls available based on text cursor movements. """ cursorInField = self.isCursorInField() fieldCount = self.fieldListBox.topLevelItemCount() self.addFieldButton.setEnabled(cursorInField == None and fieldCount) self.delFieldButton.setEnabled(cursorInField == True) self.addOperButton.setEnabled(cursorInField == None) def addField(self): """Add selected field to cursor pos in the equation editor. """ fieldSepName = '{{*{0}{1}*}}'.format(self.refLevelFlag, self.fieldListBox.currentItem(). text(0)) self.equationEdit.insert(fieldSepName) self.equationEdit.setFocus() def deleteField(self): """Remove field from cursor pos in the equation editor. """ if self.isCursorInField(True): self.equationEdit.insert('') self.equationEdit.setFocus() def addOperator(self): """Add selected operator to cursor pos in the equation editor. """ oper = self.operListBox.currentItem().text(0) origText = self.equationEdit.text() cursorPos = self.equationEdit.cursorPosition() if cursorPos != 0 and origText[cursorPos - 1] != ' ': oper = ' ' + oper self.equationEdit.insert(oper + ' ') parenPos = oper.find(')') if parenPos >= 0: cursorPos = self.equationEdit.cursorPosition() self.equationEdit.setCursorPosition(cursorPos - len(oper) + parenPos - 1) self.equationEdit.setFocus() def isCursorInField(self, selectField=False): """Return True if a field pattern encloses the cursor/selection. Return False if the selection overlaps a field. Return None if there is no field at the cursor. Arguments: selectField -- select the entire field pattern if True. """ cursorPos = self.equationEdit.cursorPosition() selectStart = self.equationEdit.selectionStart() if selectStart < 0: selectStart = cursorPos elif selectStart == cursorPos: # backward selection cursorPos += len(self.equationEdit.selectedText()) start = end = None for match in fieldPattern.finditer(self.equationEdit.text()): start = (match.start() if match.start() < selectStart < match.end() else None) end = (match.end() if match.start() < cursorPos < match.end() else None) if start != None or end != None: break if start == None and end == None: return None if start == None or end == None: return False if selectField: self.equationEdit.setSelection(start, end - start) return True def changeRefLevel(self, num): """Change the reference level based on a combobox signal. Arguments: num -- the combobox index selected """ self.refLevelFlag = _mathRefLevelFlags[num] if self.refLevelFlag in ('', '#'): self.typeCombo.setEnabled(False) self.typeCombo.setCurrentIndex(self.typeFormats.typeNames(). index(self.nodeFormat.name)) else: self.typeCombo.setEnabled(True) self.updateFieldList() def replaceOperatorList(self, num): """Change the operator list based on a signal from the oper type combo. Arguments: num -- the combobox index selected """ self.operListBox.clear() for oper, descr in _operatorLists[num]: QTreeWidgetItem(self.operListBox, [oper, descr]) self.operListBox.resizeColumnToContents(0) self.operListBox.setColumnWidth(0, int(self.operListBox.columnWidth(0) * 1.2)) self.operListBox.resizeColumnToContents(1) selectItem = self.operListBox.topLevelItem(0) self.operListBox.setCurrentItem(selectItem) selectItem.setSelected(True) def accept(self): """Verify the equation and close the dialog if acceptable. """ eqnText = self.equationEdit.text().strip() if eqnText: eqn = matheval.MathEquation(eqnText) try: eqn.validate() except ValueError as err: QMessageBox.warning(self, 'TreeLine', _('Equation error: {}').format(err)) return self.typeFormats.emptiedMathDict.setdefault(self.nodeFormat.name, set()).discard(self.field.name) self.field.equation = eqn else: if self.field.equationText(): self.typeFormats.emptiedMathDict.setdefault(self.nodeFormat. name, set()).add(self.field.name) self.field.equation = None resultStr = (_mathResultTypes[self.resultTypeCombo.currentIndex()]. split(' ', 1)[0].lower()) self.field.changeResultType(fieldformat.MathResult[resultStr]) super().accept() TreeLine-3.2.1/source/dataeditors.py000066400000000000000000003270741506556630100174250ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # dataeditors.py, provides classes for data editors in the data edit view # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import xml.sax.saxutils import os.path import sys import re import math import enum import datetime import subprocess from PyQt6.QtCore import (QDate, QDateTime, QPoint, QPointF, QRect, QSize, QTime, Qt, pyqtSignal) from PyQt6.QtGui import (QAction, QBrush, QFont, QFontMetrics, QPainter, QPainterPath, QPixmap, QPen, QTextCursor, QTextDocument, QValidator) from PyQt6.QtWidgets import (QAbstractItemView, QAbstractSpinBox, QApplication, QButtonGroup, QCalendarWidget, QCheckBox, QColorDialog, QComboBox, QDialog, QFileDialog, QHBoxLayout, QHeaderView, QLabel, QLineEdit, QMenu, QPushButton, QRadioButton, QScrollArea, QSizePolicy, QSpinBox, QTextEdit, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget) import dataeditview import fieldformat import urltools import globalref import optiondefaults multipleSpaceRegEx = re.compile(r' {2,}') class PlainTextEditor(QTextEdit): """An editor widget for multi-line plain text fields. """ dragLinkEnabled = False contentsChanged = pyqtSignal(QWidget) editEnding = pyqtSignal(QWidget) keyPressed = pyqtSignal(QWidget) def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.setAcceptRichText(False) self.setPalette(QApplication.palette()) self.setStyleSheet('QTextEdit {border: 2px solid palette(highlight)}') self.setTabChangesFocus(True) self.cursorPositionChanged.connect(self.updateActions) self.selectionChanged.connect(self.updateActions) self.allActions = parent.parent().allActions self.modified = False self.textChanged.connect(self.signalUpdate) self.allActions['FormatInsertDate'].triggered.connect(self.insDate) def setContents(self, text): """Set the contents of the editor to text. Arguments: text - the new text contents for the editor """ self.blockSignals(True) self.setPlainText(text) self.blockSignals(False) def contents(self): """Return the editor text contents. """ return self.toPlainText() def hasSelectedText(self): """Return True if text is selected. """ return self.textCursor().hasSelection() def cursorPosTuple(self): """Return a tuple of the current cursor position and anchor (integers). """ cursor = self.textCursor() return (cursor.anchor(), cursor.position()) def setCursorPos(self, anchor, position): """Set the cursor to the given anchor and position. Arguments: anchor -- the cursor selection start integer position -- the cursor position or select end integer """ cursor = self.textCursor() cursor.setPosition(anchor) cursor.setPosition(position, QTextCursor.MoveMode.KeepAnchor) self.setTextCursor(cursor) # self.ensureCursorVisible() def setCursorPoint(self, point): """Set the cursor to the given point. Arguments: point -- the QPoint for the new cursor position """ self.setTextCursor(self.cursorForPosition(self.mapFromGlobal(point))) def resetCursor(self): """Set the cursor to end for tab-focus use. """ self.moveCursor(QTextCursor.MoveOperation.End) def scrollPosition(self): """Return the current scrollbar position. """ return self.verticalScrollBar().value() def setScrollPosition(self, value): """Set the scrollbar position to value. Arguments: value -- the new scrollbar position """ self.verticalScrollBar().setValue(value) def signalUpdate(self): """Signal the delegate to update the model based on an editor change. """ self.modified = True self.contentsChanged.emit(self) def disableActions(self): """Reset action availability after focus is lost. """ try: self.allActions['EditCut'].setEnabled(True) self.allActions['EditCopy'].setEnabled(True) mime = QApplication.clipboard().mimeData() self.allActions['EditPaste'].setEnabled(len(mime.data('text/xml') or mime.data('text/plain')) > 0) self.allActions['FormatInsertDate'].setEnabled(False) except RuntimeError: pass # avoid calling a deleted C++ editor object def updateActions(self): """Set availability of context menu actions. """ hasSelection = self.textCursor().hasSelection() self.allActions['EditCut'].setEnabled(hasSelection) self.allActions['EditCopy'].setEnabled(hasSelection) mime = QApplication.clipboard().mimeData() self.allActions['EditPaste'].setEnabled(len(mime.data('text/plain')) > 0) self.allActions['FormatInsertDate'].setEnabled(True) def insDate(self): """Insert the current date using the editor format. """ date = datetime.date.today() editorFormat = fieldformat.adjOutDateFormat(globalref. genOptions['EditDateFormat']) dateText = date.strftime(editorFormat) self.insertPlainText(dateText) def contextMenuEvent(self, event): """Override popup menu to add global actions. Arguments: event -- the menu event """ menu = QMenu(self) menu.addAction(self.allActions['FormatSelectAll']) menu.addSeparator() menu.addAction(self.allActions['EditCut']) menu.addAction(self.allActions['EditCopy']) menu.addAction(self.allActions['EditPaste']) menu.addSeparator() menu.addAction(self.allActions['FormatInsertDate']) menu.exec(event.globalPos()) def focusInEvent(self, event): """Set availability and update format actions. Arguments: event -- the focus event """ super().focusInEvent(event) self.updateActions() def focusOutEvent(self, event): """Reset format actions on focus loss if not focusing a menu. Arguments: event -- the focus event """ super().focusOutEvent(event) if event.reason() != Qt.FocusReason.PopupFocusReason: self.disableActions() self.editEnding.emit(self) def hideEvent(self, event): """Reset format actions when the editor is hidden. Arguments: event -- the hide event """ self.disableActions() self.editEnding.emit(self) super().hideEvent(event) def keyPressEvent(self, event): """Emit a signal after every key press and handle page up/down. Needed to adjust scroll position in unlimited height editors. Arguments: event -- the key press event """ if (event.key() in (Qt.Key.Key_PageUp, Qt.Key.Key_PageDown) and not globalref.genOptions['EditorLimitHeight']): pos = self.cursorRect().center() if event.key() == Qt.Key.Key_PageUp: pos.setY(pos.y() - self.parent().height()) if pos.y() < 0: pos.setY(0) else: pos.setY(pos.y() + self.parent().height()) if pos.y() > self.height(): pos.setY(self.height()) newCursor = self.cursorForPosition(pos) if event.modifiers() == Qt.KeyboardModifier.ShiftModifier: cursor = self.textCursor() cursor.setPosition(newCursor.position(), QTextCursor.MoveMode.KeepAnchor) self.setTextCursor(cursor) else: self.setTextCursor(newCursor) event.accept() self.keyPressed.emit(self) return super().keyPressEvent(event) self.keyPressed.emit(self) class HtmlTextEditor(PlainTextEditor): """An editor for HTML fields, plain text with HTML insert commands. """ htmlFontSizes = ('small', '', 'large', 'x-large', 'xx-large') dragLinkEnabled = True inLinkSelectMode = pyqtSignal(bool) def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.intLinkDialog = None self.nodeRef = None self.allActions['FormatBoldFont'].triggered.connect(self.setBoldFont) self.allActions['FormatItalicFont'].triggered.connect(self. setItalicFont) self.allActions['FormatUnderlineFont'].triggered.connect(self. setUnderlineFont) self.allActions['FormatStrikethroughFont'].triggered.connect(self. setStrikethroughFont) self.allActions['FormatFontSize'].parent().triggered.connect(self. setFontSize) self.allActions['FormatFontSize'].triggered.connect(self. showFontSizeMenu) self.allActions['FormatFontColor'].triggered.connect(self.setFontColor) self.allActions['FormatExtLink'].triggered.connect(self.setExtLink) self.allActions['FormatIntLink'].triggered.connect(self.setIntLink) def insertTagText(self, prefix, suffix): """Insert given tag text and maintain the original selection. Arguments: prefix -- the opening tag suffix -- the closing tag """ cursor = self.textCursor() start = cursor.selectionStart() end = cursor.selectionEnd() text = '{0}{1}{2}'.format(prefix, cursor.selectedText(), suffix) self.insertPlainText(text) cursor.setPosition(start + len(prefix)) cursor.setPosition(end + len(prefix), QTextCursor.MoveMode.KeepAnchor) self.setTextCursor(cursor) def setBoldFont(self, checked): """Insert tags for a bold font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus() and checked: self.insertTagText('', '') except RuntimeError: pass # avoid calling a deleted C++ editor object def setItalicFont(self, checked): """Insert tags for an italic font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus() and checked: self.insertTagText('', '') except RuntimeError: pass # avoid calling a deleted C++ editor object def setUnderlineFont(self, checked): """Insert tags for an underline font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus() and checked: self.insertTagText('', '') except RuntimeError: pass # avoid calling a deleted C++ editor object def setStrikethroughFont(self, checked): """Insert tags for a strikethrough font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus() and checked: self.insertTagText('', '') except RuntimeError: pass # avoid calling a deleted C++ editor object def setFontSize(self, action): """Set the font size of the selection or the current setting. Arguments: action -- the sub-menu action that was picked """ try: if self.hasFocus(): actions = self.allActions['FormatFontSize'].parent().actions() sizeNum = actions.index(action) size = HtmlTextEditor.htmlFontSizes[sizeNum] self.insertTagText(''.format(size), '') except RuntimeError: pass # avoid calling a deleted C++ editor object def setFontColor(self): """Set the font color of the selection or the current setting. Prompt the user for a color using a dialog. """ try: if self.hasFocus(): charFormat = self.currentCharFormat() oldColor = charFormat.foreground().color() newColor = QColorDialog.getColor(oldColor, self) if newColor.isValid(): self.insertTagText(''. format(newColor.name()), '') except RuntimeError: pass # avoid calling a deleted C++ editor object def setExtLink(self): """Add or modify an extrnal web link at the cursor. """ try: if self.hasFocus(): dialog = ExtLinkDialog(False, self) address, name = self.selectLink() if address.startswith('#'): address = name = '' dialog.setFromComponents(address, name) if dialog.exec() == QDialog.DialogCode.Accepted: self.insertPlainText(dialog.htmlText()) except RuntimeError: pass # avoid calling a deleted C++ editor object def setIntLink(self): """Show dialog to add or modify an internal node link at the cursor. """ try: if self.hasFocus(): self.intLinkDialog = EmbedIntLinkDialog(self.nodeRef. treeStructureRef(), self) address, name = self.selectLink() if address.startswith('#'): address = address.lstrip('#') else: address = '' self.intLinkDialog.setFromComponents(address, name) self.intLinkDialog.finished.connect(self.insertInternalLink) self.intLinkDialog.show() self.inLinkSelectMode.emit(True) except RuntimeError: pass # avoid calling a deleted C++ editor object def insertInternalLink(self, resultCode): """Add or modify an internal node link based on dialog approval. Arguments: resultCode -- the result from the dialog (OK or cancel) """ if resultCode == QDialog.DialogCode.Accepted: self.insertPlainText(self.intLinkDialog.htmlText()) self.intLinkDialog = None self.inLinkSelectMode.emit(False) def setLinkFromNode(self, node): """Set the current internal link from a clicked node. Arguments: node -- the node to set the unique ID from """ if self.intLinkDialog: self.intLinkDialog.setFromNode(node) def selectLink(self): """Select the full link at the cursor, return link data. Any links at the cursor or partially selected are fully selected. Returns a tuple of the link address and name, or a tuple with empty strings if none are found. """ cursor = self.textCursor() anchor = cursor.anchor() position = cursor.position() for match in fieldformat.linkRegExp.finditer(self.toPlainText()): start = match.start() end = match.end() if start < anchor < end or start < position < end: address, name = match.groups() cursor.setPosition(start) cursor.setPosition(end, QTextCursor.MoveMode.KeepAnchor) self.setTextCursor(cursor) return (address, name) return ('', cursor.selectedText()) def addDroppedUrl(self, urlText): """Add the URL link that was dropped on this editor from the view. Arguments: urlText -- the text of the link """ name = urltools.shortName(urlText) text = '{1}'.format(urlText, name) self.insertPlainText(text) def disableActions(self): """Set format actions to unavailable. """ super().disableActions() try: self.allActions['FormatBoldFont'].setEnabled(False) self.allActions['FormatItalicFont'].setEnabled(False) self.allActions['FormatUnderlineFont'].setEnabled(False) self.allActions['FormatStrikethroughFont'].setEnabled(False) self.allActions['FormatFontSize'].parent().setEnabled(False) self.allActions['FormatFontColor'].setEnabled(False) self.allActions['FormatExtLink'].setEnabled(False) self.allActions['FormatIntLink'].setEnabled(False) except RuntimeError: pass # avoid calling a deleted C++ editor object def updateActions(self): """Set editor format actions to available and update toggle states. """ super().updateActions() boldFontAct = self.allActions['FormatBoldFont'] boldFontAct.setEnabled(True) boldFontAct.setChecked(False) italicAct = self.allActions['FormatItalicFont'] italicAct.setEnabled(True) italicAct.setChecked(False) underlineAct = self.allActions['FormatUnderlineFont'] underlineAct.setEnabled(True) underlineAct.setChecked(False) strikethroughAct = self.allActions['FormatStrikethroughFont'] strikethroughAct.setEnabled(True) strikethroughAct.setChecked(False) fontSizeSubMenu = self.allActions['FormatFontSize'].parent() fontSizeSubMenu.setEnabled(True) for action in fontSizeSubMenu.actions(): action.setChecked(False) self.allActions['FormatFontColor'].setEnabled(True) self.allActions['FormatExtLink'].setEnabled(True) self.allActions['FormatIntLink'].setEnabled(True) def showFontSizeMenu(self): """Show a context menu for font size at this edit box. """ if self.hasFocus(): rect = self.rect() pt = self.mapToGlobal(QPoint(rect.center().x(), rect.bottom())) self.allActions['FormatFontSize'].parent().popup(pt) def contextMenuEvent(self, event): """Override popup menu to add formatting and global actions. Arguments: event -- the menu event """ menu = QMenu(self) menu.addAction(self.allActions['FormatBoldFont']) menu.addAction(self.allActions['FormatItalicFont']) menu.addAction(self.allActions['FormatUnderlineFont']) menu.addAction(self.allActions['FormatStrikethroughFont']) menu.addSeparator() menu.addMenu(self.allActions['FormatFontSize'].parent()) menu.addAction(self.allActions['FormatFontColor']) menu.addSeparator() menu.addAction(self.allActions['FormatExtLink']) menu.addAction(self.allActions['FormatIntLink']) menu.addAction(self.allActions['FormatInsertDate']) menu.addSeparator() menu.addAction(self.allActions['FormatSelectAll']) menu.addSeparator() menu.addAction(self.allActions['EditCut']) menu.addAction(self.allActions['EditCopy']) menu.addAction(self.allActions['EditPaste']) menu.exec(event.globalPos()) def hideEvent(self, event): """Close the internal link dialog when the editor is hidden. Arguments: event -- the hide event """ if self.intLinkDialog: self.intLinkDialog.close() self.intLinkDialog = None super().hideEvent(event) class RichTextEditor(HtmlTextEditor): """An editor widget for multi-line wysiwyg rich text fields. """ fontPointSizes = [] def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.setAcceptRichText(True) if not RichTextEditor.fontPointSizes: doc = QTextDocument() doc.setDefaultFont(self.font()) for sizeName in HtmlTextEditor.htmlFontSizes: if sizeName: doc.setHtml('text'. format(sizeName)) pointSize = (QTextCursor(doc).charFormat().font(). pointSize()) else: pointSize = self.font().pointSize() RichTextEditor.fontPointSizes.append(pointSize) self.allActions['FormatClearFormat'].triggered.connect(self. setClearFormat) self.allActions['EditPastePlain'].triggered.connect(self.pastePlain) def setContents(self, text): """Set the contents of the editor to text. Arguments: text - the new text contents for the editor """ self.blockSignals(True) self.setHtml(text) self.blockSignals(False) def contents(self): """Return simplified HTML code for the editor contents. Replace Unicode line feeds with HTML breaks, escape <, >, &, and replace some rich formatting with HTML tags. """ doc = self.document() block = doc.begin() result = '' while block.isValid(): if result: result += '
    ' fragIter = block.begin() while not fragIter.atEnd(): text = xml.sax.saxutils.escape(fragIter.fragment().text()) text = text.replace('\u2028', '
    ') charFormat = fragIter.fragment().charFormat() if charFormat.fontWeight() >= QFont.Weight.Bold: text = '{0}'.format(text) if charFormat.fontItalic(): text = '{0}'.format(text) if charFormat.fontStrikeOut(): text = '{0}'.format(text) size = charFormat.font().pointSize() if size != self.font().pointSize(): closeSize = min((abs(size - i), i) for i in RichTextEditor.fontPointSizes)[1] sizeNum = RichTextEditor.fontPointSizes.index(closeSize) htmlSize = HtmlTextEditor.htmlFontSizes[sizeNum] if htmlSize: text = ('{1}'. format(htmlSize, text)) if charFormat.anchorHref(): text = '{1}'.format(charFormat. anchorHref(), text) else: # ignore underline and font color for links if charFormat.fontUnderline(): text = '{0}'.format(text) if (charFormat.foreground().color().name() != block.charFormat().foreground().color().name()): text = ('{1}'. format(charFormat.foreground().color().name(), text)) result += text fragIter += 1 block = block.next() return result def setBoldFont(self, checked): """Set the selection or the current setting to a bold font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus(): if checked: self.setFontWeight(QFont.Weight.Bold) else: self.setFontWeight(QFont.Weight.Normal) except RuntimeError: pass # avoid calling a deleted C++ editor object def setItalicFont(self, checked): """Set the selection or the current setting to an italic font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus(): self.setFontItalic(checked) except RuntimeError: pass # avoid calling a deleted C++ editor object def setUnderlineFont(self, checked): """Set the selection or the current setting to an underlined font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus(): self.setFontUnderline(checked) except RuntimeError: pass # avoid calling a deleted C++ editor object def setStrikethroughFont(self, checked): """Set the selection or the current setting to a strikethrough font. Arguments: checked -- current toggle state of the control """ try: if self.hasFocus(): charFormat = self.currentCharFormat() charFormat.setFontStrikeOut(checked) self.setCurrentCharFormat(charFormat) except RuntimeError: pass # avoid calling a deleted C++ editor object def setFontSize(self, action): """Set the font size of the selection or the current setting. Arguments: action -- the sub-menu action that was picked """ try: if self.hasFocus(): actions = self.allActions['FormatFontSize'].parent().actions() sizeNum = actions.index(action) pointSize = RichTextEditor.fontPointSizes[sizeNum] charFormat = self.currentCharFormat() charFormat.setFontPointSize(pointSize) self.setCurrentCharFormat(charFormat) except RuntimeError: pass # avoid calling a deleted C++ editor object def setFontColor(self): """Set the font color of the selection or the current setting. Prompt the user for a color using a dialog. """ try: if self.hasFocus(): charFormat = self.currentCharFormat() oldColor = charFormat.foreground().color() newColor = QColorDialog.getColor(oldColor, self) if newColor.isValid(): charFormat.setForeground(QBrush(newColor)) self.setCurrentCharFormat(charFormat) except RuntimeError: pass # avoid calling a deleted C++ editor object def setClearFormat(self): """Clear the current or selected text formatting. """ try: if self.hasFocus(): self.setCurrentFont(self.font()) charFormat = self.currentCharFormat() charFormat.clearForeground() charFormat.setAnchor(False) charFormat.setAnchorHref('') self.setCurrentCharFormat(charFormat) except RuntimeError: pass # avoid calling a deleted C++ editor object def setExtLink(self): """Add or modify an extrnal web link at the cursor. """ try: if self.hasFocus(): dialog = ExtLinkDialog(False, self) address, name = self.selectLink() if address.startswith('#'): address = name = '' dialog.setFromComponents(address, name) if dialog.exec() == QDialog.DialogCode.Accepted: if self.textCursor().hasSelection(): self.insertHtml(dialog.htmlText()) else: self.insertHtml(dialog.htmlText() + ' ') except RuntimeError: pass # avoid calling a deleted C++ editor object def insertInternalLink(self, resultCode): """Add or modify an internal node link based on dialog approval. Arguments: resultCode -- the result from the dialog (OK or cancel) """ if resultCode == QDialog.DialogCode.Accepted: if self.textCursor().hasSelection(): self.insertHtml(self.intLinkDialog.htmlText()) else: self.insertHtml(self.intLinkDialog.htmlText() + ' ') self.intLinkDialog = None self.inLinkSelectMode.emit(False) def selectLink(self): """Select the full link at the cursor, return link data. Any links at the cursor or partially selected are fully selected. Returns a tuple of the link address and name, or a tuple with empty strings if none are found. """ cursor = self.textCursor() if not cursor.hasSelection() and not cursor.charFormat().anchorHref(): return ('', '') selectText = cursor.selection().toPlainText() anchorCursor = QTextCursor(self.document()) anchorCursor.setPosition(cursor.anchor()) cursor.clearSelection() if cursor < anchorCursor: anchorCursor, cursor = cursor, anchorCursor position = cursor.position() address = name = '' if anchorCursor.charFormat().anchorHref(): fragIter = anchorCursor.block().begin() while not (fragIter.fragment().contains(anchorCursor.position()) or fragIter.fragment().contains(anchorCursor.position() - 1)): fragIter += 1 fragment = fragIter.fragment() anchorCursor.setPosition(fragment.position()) address = fragment.charFormat().anchorHref() name = fragment.text() if cursor.charFormat().anchorHref(): fragIter = cursor.block().begin() while not (fragIter.fragment().contains(cursor.position()) or fragIter.fragment().contains(cursor.position() - 1)): fragIter += 1 fragment = fragIter.fragment() position = fragment.position() + fragment.length() address = fragment.charFormat().anchorHref() name = fragment.text() if not name: name = selectText.split('\n')[0] cursor.setPosition(anchorCursor.position()) cursor.setPosition(position, QTextCursor.MoveMode.KeepAnchor) self.setTextCursor(cursor) return (address, name) def addDroppedUrl(self, urlText): """Add the URL link that was dropped on this editor from the view. Arguments: urlText -- the text of the link """ name = urltools.shortName(urlText) text = '{1}'.format(urlText, name) if not self.textCursor().hasSelection(): text += ' ' self.insertHtml(text) def pastePlain(self): """Paste non-formatted text from the clipboard. """ text = QApplication.clipboard().mimeData().text() if text and self.hasFocus(): self.insertPlainText(text) def disableActions(self): """Set format actions to unavailable. """ super().disableActions() try: self.allActions['FormatClearFormat'].setEnabled(False) self.allActions['EditPastePlain'].setEnabled(False) except RuntimeError: pass # avoid calling a deleted C++ editor object def updateActions(self): """Set editor format actions to available and update toggle states. """ super().updateActions() self.allActions['FormatBoldFont'].setChecked(self.fontWeight() == QFont.Weight.Bold) self.allActions['FormatItalicFont'].setChecked(self.fontItalic()) self.allActions['FormatUnderlineFont'].setChecked(self.fontUnderline()) self.allActions['FormatStrikethroughFont'].setChecked(self. currentCharFormat().fontStrikeOut()) fontSizeSubMenu = self.allActions['FormatFontSize'].parent() pointSize = int(self.fontPointSize()) try: sizeNum = RichTextEditor.fontPointSizes.index(pointSize) except ValueError: sizeNum = 1 # default size fontSizeSubMenu.actions()[sizeNum].setChecked(True) self.allActions['FormatClearFormat'].setEnabled(True) mime = QApplication.clipboard().mimeData() self.allActions['EditPastePlain'].setEnabled(len(mime. data('text/plain')) > 0) def contextMenuEvent(self, event): """Override popup menu to add formatting and global actions. Arguments: event -- the menu event """ menu = QMenu(self) menu.addAction(self.allActions['FormatBoldFont']) menu.addAction(self.allActions['FormatItalicFont']) menu.addAction(self.allActions['FormatUnderlineFont']) menu.addAction(self.allActions['FormatStrikethroughFont']) menu.addSeparator() menu.addMenu(self.allActions['FormatFontSize'].parent()) menu.addAction(self.allActions['FormatFontColor']) menu.addSeparator() menu.addAction(self.allActions['FormatExtLink']) menu.addAction(self.allActions['FormatIntLink']) menu.addAction(self.allActions['FormatInsertDate']) menu.addSeparator() menu.addAction(self.allActions['FormatSelectAll']) menu.addAction(self.allActions['FormatClearFormat']) menu.addSeparator() menu.addAction(self.allActions['EditCut']) menu.addAction(self.allActions['EditCopy']) menu.addAction(self.allActions['EditPaste']) menu.addAction(self.allActions['EditPastePlain']) menu.exec(event.globalPos()) def mousePressEvent(self, event): """Handle ctrl + click to follow links. Arguments: event -- the mouse event """ if (event.button() == Qt.MouseButton.LeftButton and event.modifiers() == Qt.KeyboardModifier.ControlModifier): cursor = self.cursorForPosition(event.position().toPoint()) address = cursor.charFormat().anchorHref() if address: if address.startswith('#'): editView = self.parent().parent() selectModel = editView.treeView.selectionModel() selectModel.selectNodeById(address[1:]) else: # check for relative path if urltools.isRelative(address): defaultPath = str(globalref.mainControl. defaultPathObj(True)) address = urltools.toAbsolute(address, defaultPath) openExtUrl(address) event.accept() else: super().mousePressEvent(event) class OneLineTextEditor(RichTextEditor): """An editor widget for single-line wysiwyg rich text fields. """ def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) def insertFromMimeData(self, mimeSource): """Override to verify that only a single line is pasted or dropped. Arguments: mimeSource -- the mime source to be inserted """ super().insertFromMimeData(mimeSource) text = self.contents() if '
    ' in text: text = text.split('
    ', 1)[0] self.blockSignals(True) self.setHtml(text) self.blockSignals(False) self.moveCursor(QTextCursor.MoveOperation.End) def keyPressEvent(self, event): """Customize handling of return and control keys. Arguments: event -- the key press event """ if event.key() not in (Qt.Key.Key_Enter, Qt.Key.Key_Return): super().keyPressEvent(event) class LineEditor(QLineEdit): """An editor widget for unformatted single-line fields. Used both stand-alone and as part of the combo box editor. """ dragLinkEnabled = False contentsChanged = pyqtSignal(QWidget) editEnding = pyqtSignal(QWidget) contextMenuPrep = pyqtSignal() def __init__(self, parent=None, subControl=False): """Initialize the editor class. Includes a colored triangle error flag for non-matching formats. Arguments: parent -- the parent, if given subcontrol -- true if used inside a combo box (no border or signal) """ super().__init__(parent) self.setPalette(QApplication.palette()) self.cursorPositionChanged.connect(self.updateActions) self.selectionChanged.connect(self.updateActions) try: self.allActions = parent.parent().allActions except AttributeError: # view is a level up if embedded in a combo self.allActions = parent.parent().parent().allActions self.modified = False self.errorFlag = False self.savedCursorPos = None self.extraMenuActions = [] if not subControl: self.setStyleSheet('QLineEdit {border: 2px solid ' 'palette(highlight)}') self.textEdited.connect(self.signalUpdate) def setContents(self, text): """Set the contents of the editor to text. Arguments: text - the new text contents for the editor """ self.setText(text) def contents(self): """Return the editor text contents. """ return self.text() def signalUpdate(self): """Signal the delegate to update the model based on an editor change. """ self.modified = True self.errorFlag = False self.contentsChanged.emit(self) def setErrorFlag(self): """Set the error flag to True and repaint the widget. """ self.errorFlag = True self.update() def cursorPosTuple(self): """Return a tuple of the current cursor position and anchor (integers). """ pos = start = self.cursorPosition() if self.hasSelectedText(): start = self.selectionStart() return (start, pos) def setCursorPos(self, anchor, position): """Set the cursor to the given anchor and position. Arguments: anchor -- the cursor selection start integer position -- the cursor position or select end integer """ if anchor == position: self.deselect() self.setCursorPosition(position) else: self.setSelection(anchor, position - anchor) def setCursorPoint(self, point): """Set the cursor to the given point. Arguments: point -- the QPoint for the new cursor position """ self.savedCursorPos = self.cursorPositionAt(self.mapFromGlobal(point)) self.setCursorPosition(self.savedCursorPos) def resetCursor(self): """Set the cursor to select all for tab-focus use. """ self.selectAll() def scrollPosition(self): """Return the current scrollbar position. """ return 0 def setScrollPosition(self, value): """Set the scrollbar position to value. No operation with single line editor. Arguments: value -- the new scrollbar position """ pass def paintEvent(self, event): """Add painting of the error flag to the paint event. Arguments: event -- the paint event """ super().paintEvent(event) if self.errorFlag: painter = QPainter(self) path = QPainterPath(QPointF(0, 0)) path.lineTo(0, 10) path.lineTo(10, 0) path.closeSubpath() painter.fillPath(path, QApplication.palette().highlight()) def disableActions(self): """Reset action availability after focus is lost. """ try: self.allActions['EditCut'].setEnabled(True) self.allActions['EditCopy'].setEnabled(True) mime = QApplication.clipboard().mimeData() self.allActions['EditPaste'].setEnabled(len(mime.data('text/xml') or mime.data('text/plain')) > 0) except RuntimeError: pass # avoid calling a deleted C++ editor object def updateActions(self): """Set availability of context menu actions. """ hasSelection = self.hasSelectedText() self.allActions['EditCut'].setEnabled(hasSelection) self.allActions['EditCopy'].setEnabled(hasSelection) mime = QApplication.clipboard().mimeData() self.allActions['EditPaste'].setEnabled(len(mime.data('text/plain')) > 0) def contextMenuEvent(self, event): """Override popup menu to add formatting actions. Arguments: event -- the menu event """ self.contextMenuPrep.emit() menu = QMenu(self) if self.extraMenuActions: for action in self.extraMenuActions: menu.addAction(action) menu.addSeparator() menu.addAction(self.allActions['FormatSelectAll']) menu.addSeparator() menu.addAction(self.allActions['EditCut']) menu.addAction(self.allActions['EditCopy']) menu.addAction(self.allActions['EditPaste']) menu.exec(event.globalPos()) def focusInEvent(self, event): """Restore a saved cursor position for new editors. Arguments: event -- the focus event """ super().focusInEvent(event) if (event.reason() == Qt.FocusReason.OtherFocusReason and self.savedCursorPos != None): self.setCursorPosition(self.savedCursorPos) self.savedCursorPos = None self.updateActions() def focusOutEvent(self, event): """Reset format actions on focus loss if not focusing a menu. Arguments: event -- the focus event """ super().focusOutEvent(event) if event.reason() != Qt.FocusReason.PopupFocusReason: self.disableActions() self.editEnding.emit(self) def hideEvent(self, event): """Reset format actions when the editor is hidden. Arguments: event -- the hide event """ self.disableActions() self.editEnding.emit(self) super().hideEvent(event) class ReadOnlyEditor(LineEditor): """An editor widget that doesn't allow any edits. """ def __init__(self, parent=None): """Initialize the editor class. Includes a colored triangle error flag for non-matching formats. Arguments: parent -- the parent, if given """ super().__init__(parent, True) self.setReadOnly(True) self.setStyleSheet('QLineEdit {border: 2px solid palette(highlight); ' 'background-color: palette(button)}') class ComboEditor(QComboBox): """A general combo box editor widget. Uses the LineEditor class to paint the error flag. """ dragLinkEnabled = False contentsChanged = pyqtSignal(QWidget) editEnding = pyqtSignal(QWidget) def __init__(self, parent=None): """Initialize the editor class. The self.fieldRef and self.nodeRef must be set after creation. Arguments: parent -- the parent, if given """ super().__init__(parent) self.setPalette(QApplication.palette()) self.setStyleSheet('QComboBox {border: 2px solid palette(highlight)}') self.setEditable(True) self.setLineEdit(LineEditor(self, True)) self.listView = QTreeWidget() self.listView.setColumnCount(2) self.listView.header().hide() self.listView.setRootIsDecorated(False) self.listView.setSelectionBehavior(QAbstractItemView. SelectionBehavior.SelectRows) self.listView.header().setSectionResizeMode(QHeaderView.ResizeMode. ResizeToContents) self.setModel(self.listView.model()) self.setView(self.listView) self.setModelColumn(0) self.modified = False self.fieldRef = None self.nodeRef = None self.editTextChanged.connect(self.signalUpdate) self.lineEdit().editEnding.connect(self.signalEditEnd) def setContents(self, text): """Set the contents of the editor to text. Arguments: text - the new text contents for the editor """ self.blockSignals(True) self.setEditText(text) self.blockSignals(False) def contents(self): """Return the editor text contents. """ return self.currentText() def showPopup(self): """Load combo box with choices before showing it. """ self.listView.setColumnCount(self.fieldRef.numChoiceColumns) text = self.currentText() if self.fieldRef.autoAddChoices: self.fieldRef.clearChoices() for node in self.nodeRef.treeStructureRef().nodeDict.values(): if node.formatRef == self.nodeRef.formatRef: self.fieldRef.addChoice(node.data.get(self.fieldRef.name, '')) self.blockSignals(True) self.clear() if self.fieldRef.numChoiceColumns == 1: choices = self.fieldRef.comboChoices() self.addItems(choices) else: annotatedChoices = self.fieldRef.annotatedComboChoices(text) for choice, annot in annotatedChoices: QTreeWidgetItem(self.listView, [choice, annot]) choices = [choice for (choice, annot) in annotatedChoices] try: self.setCurrentIndex(choices.index(text)) except ValueError: self.setEditText(text) self.blockSignals(False) super().showPopup() def signalUpdate(self): """Signal the delegate to update the model based on an editor change. """ self.modified = True self.lineEdit().errorFlag = False self.contentsChanged.emit(self) def setErrorFlag(self): """Set the error flag to True and repaint the widget. """ self.lineEdit().errorFlag = True self.update() def hasSelectedText(self): """Return True if text is selected. """ return self.lineEdit().hasSelectedText() def selectAll(self): """Select all text in the line editor. """ self.lineEdit().selectAll() def cursorPosTuple(self): """Return a tuple of the current cursor position and anchor (integers). """ return self.lineEdit().cursorPosTuple() def setCursorPos(self, anchor, position): """Set the cursor to the given anchor and position. Arguments: anchor -- the cursor selection start integer position -- the cursor position or select end integer """ self.lineEdit().setCursorPos(anchor, position) def setCursorPoint(self, point): """Set the cursor to the given point. Arguments: point -- the QPoint for the new cursor position """ self.lineEdit().setCursorPoint(point) def resetCursor(self): """Set the cursor to select all for tab-focus use. """ self.lineEdit().selectAll() def scrollPosition(self): """Return the current scrollbar position. """ return 0 def setScrollPosition(self, value): """Set the scrollbar position to value. No operation with single line editor. Arguments: value -- the new scrollbar position """ pass def copy(self): """Copy text selected in the line editor. """ self.lineEdit().copy() def cut(self): """Cut text selected in the line editor. """ self.lineEdit().cut() def paste(self): """Paste from the clipboard into the line editor. """ self.lineEdit().paste() def signalEditEnd(self): """Emit editEnding signal based on line edit signal. """ self.editEnding.emit(self) class CombinationEditor(ComboEditor): """An editor widget for combination and auto-combination fields. Uses a combo box with a list of checkboxes in place of the list popup. """ def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.checkBoxDialog = None def showPopup(self): """Override to show a popup entry widget in place of a list view. """ if self.fieldRef.autoAddChoices: self.fieldRef.clearChoices() for node in self.nodeRef.treeStructureRef().nodeDict.values(): if node.formatRef == self.nodeRef.formatRef: self.fieldRef.addChoice(node.data.get(self.fieldRef.name, '')) selectList = self.fieldRef.comboActiveChoices(self.currentText()) self.checkBoxDialog = CombinationDialog(self.fieldRef.comboChoices(), selectList, self) self.checkBoxDialog.setMinimumWidth(self.width()) self.checkBoxDialog.buttonChanged.connect(self.updateText) self.checkBoxDialog.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.checkBoxDialog.width() + 1) screenBottom = (QApplication.primaryScreen().availableGeometry(). bottom()) if pos.y() + self.checkBoxDialog.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.checkBoxDialog.height()) self.checkBoxDialog.move(pos) def hidePopup(self): """Override to hide the popup entry widget. """ if self.checkBoxDialog: self.checkBoxDialog.hide() super().hidePopup() def updateText(self): """Update the text based on a changed signal. """ if self.checkBoxDialog: self.setEditText(self.fieldRef.joinText(self.checkBoxDialog. selectList())) class CombinationDialog(QDialog): """A popup dialog box for combination and auto-combination fields. """ buttonChanged = pyqtSignal() def __init__(self, choiceList, selectList, parent=None): """Initialize the combination dialog. Arguments: choiceList -- a list of text choices selectList -- a lit of choices to preselect parent -- the parent, if given """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Popup) topLayout = QVBoxLayout(self) topLayout.setContentsMargins(0, 0, 0, 0) scrollArea = QScrollArea() scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) topLayout.addWidget(scrollArea) innerWidget = QWidget() innerLayout = QVBoxLayout(innerWidget) selected = set(selectList) self.buttonGroup = QButtonGroup(self) self.buttonGroup.setExclusive(False) self.buttonGroup.buttonClicked.connect(self.buttonChanged) for text in choiceList: button = QCheckBox(text, innerWidget) if text in selected: button.setChecked(True) self.buttonGroup.addButton(button) innerLayout.addWidget(button) scrollArea.setWidget(innerWidget) buttons = self.buttonGroup.buttons() if buttons: buttons[0].setFocus() def selectList(self): """Return a list of currently checked text. """ result = [] for button in self.buttonGroup.buttons(): if button.isChecked(): result.append(button.text()) return result class DateEditor(ComboEditor): """An editor widget for date fields. Uses a combo box with a calendar widget in place of the list popup. """ def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.calendar = None nowAction = QAction(_('Today\'s &Date'), self) nowAction.triggered.connect(self.setNow) self.lineEdit().extraMenuActions = [nowAction] def editorDate(self): """Return the date (as a QDate) set in the line editor. If none or invalid, return an invalid date. """ try: dateStr = self.fieldRef.storedText(self.currentText()) except ValueError: return QDate() return QDate.fromString(dateStr, Qt.DateFormat.ISODate) def showPopup(self): """Override to show a calendar widget in place of a list view. """ if not self.calendar: self.calendar = QCalendarWidget(self) self.calendar.setWindowFlags(Qt.WindowType.Popup) weekStart = optiondefaults.daysOfWeek.index(globalref. genOptions['WeekStart']) self.calendar.setFirstDayOfWeek(Qt.DayOfWeek(weekStart + 1)) self.calendar.setVerticalHeaderFormat(QCalendarWidget. VerticalHeaderFormat. NoVerticalHeader) self.calendar.clicked.connect(self.setDate) date = self.editorDate() if date.isValid(): self.calendar.setSelectedDate(date) self.calendar.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.calendar.width()) screenBottom = (QApplication.primaryScreen().availableGeometry(). bottom()) if pos.y() + self.calendar.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.calendar.height()) self.calendar.move(pos) def hidePopup(self): """Override to hide the calendar widget. """ if self.calendar: self.calendar.hide() super().hidePopup() def setDate(self, date): """Set the date based on a signal from the calendar popup. Arguments: date -- the QDate to be set """ dateStr = date.toString(Qt.DateFormat.ISODate) self.setEditText(self.fieldRef.formatEditorText(dateStr)) self.calendar.hide() def setNow(self): """Set to today's date. """ dateStr = QDate.currentDate().toString(Qt.DateFormat.ISODate) self.setEditText(self.fieldRef.formatEditorText(dateStr)) class TimeEditor(ComboEditor): """An editor widget for time fields. Adds a clock popup dialog and a "now" right-click menu action. """ def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.dialog = None nowAction = QAction(_('Set to &Now'), self) nowAction.triggered.connect(self.setNow) self.lineEdit().extraMenuActions = [nowAction] def showPopup(self): """Override to show a popup entry widget in place of a list view. """ if not self.dialog: self.dialog = TimeDialog(self) self.dialog.contentsChanged.connect(self.setTime) self.dialog.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.dialog.width() + 1) screenBottom = QApplication.primaryScreen().availableGeometry().bottom() if pos.y() + self.dialog.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.dialog.height()) self.dialog.move(pos) try: storedText = self.fieldRef.storedText(self.currentText()) except ValueError: storedText = '' if storedText: self.dialog.setTimeFromText(storedText) def hidePopup(self): """Override to hide the popup entry widget. """ if self.dialog: self.dialog.hide() super().hidePopup() def setTime(self): """Set the time fom the dialog. """ if self.dialog: timeStr = self.dialog.timeObject().isoformat() + '.000' self.setEditText(self.fieldRef.formatEditorText(timeStr)) def setNow(self): """Set to the current time. """ timeStr = QTime.currentTime().toString('hh:mm:ss.zzz') self.setEditText(self.fieldRef.formatEditorText(timeStr)) TimeElem = enum.Enum('TimeElem', 'hour minute second') class TimeDialog(QDialog): """A popup clock dialog for time editing. """ contentsChanged = pyqtSignal() def __init__(self, addCalendar=False, parent=None): """Initialize the dialog widgets. Arguments: parent -- the dialog's parent widget """ super().__init__(parent) self.focusElem = None self.setWindowFlags(Qt.WindowType.Popup) horizLayout = QHBoxLayout(self) if addCalendar: self.calendar = QCalendarWidget() horizLayout.addWidget(self.calendar) weekStart = optiondefaults.daysOfWeek.index(globalref. genOptions['WeekStart']) self.calendar.setFirstDayOfWeek(Qt.DayOfWeek(weekStart + 1)) self.calendar.setVerticalHeaderFormat(QCalendarWidget. VerticalHeaderFormat. NoVerticalHeader) self.calendar.clicked.connect(self.contentsChanged) vertLayout = QVBoxLayout() horizLayout.addLayout(vertLayout) upperLayout = QHBoxLayout() vertLayout.addLayout(upperLayout) upperLayout.addStretch(0) self.hourBox = TimeSpinBox(TimeElem.hour, 1, 12, False) upperLayout.addWidget(self.hourBox) self.hourBox.valueChanged.connect(self.signalUpdate) self.hourBox.focusChanged.connect(self.handleFocusChange) colon = QLabel(':') upperLayout.addWidget(colon) self.minuteBox = TimeSpinBox(TimeElem.minute, 0, 59, True) upperLayout.addWidget(self.minuteBox) self.minuteBox.valueChanged.connect(self.signalUpdate) self.minuteBox.focusChanged.connect(self.handleFocusChange) colon = QLabel(':') upperLayout.addWidget(colon) self.secondBox = TimeSpinBox(TimeElem.second, 0, 59, True) upperLayout.addWidget(self.secondBox) self.secondBox.valueChanged.connect(self.signalUpdate) self.secondBox.focusChanged.connect(self.handleFocusChange) self.amPmBox = AmPmSpinBox() upperLayout.addSpacing(4) upperLayout.addWidget(self.amPmBox) self.amPmBox.valueChanged.connect(self.signalUpdate) upperLayout.addStretch(0) lowerLayout = QHBoxLayout() vertLayout.addLayout(lowerLayout) self.clock = ClockWidget() lowerLayout.addWidget(self.clock, Qt.AlignmentFlag.AlignCenter) self.clock.numClicked.connect(self.setFromClock) if addCalendar: self.calendar.setFocus() self.updateClock() else: self.hourBox.setFocus() self.hourBox.selectAll() def setTimeFromText(self, text): """Set the time dialog from a string. Arguments: text -- the time in ISO format """ time = (datetime.datetime. strptime(text, fieldformat.TimeField.isoFormat).time()) hour = time.hour if time.hour <= 12 else time.hour - 12 self.blockSignals(True) self.hourBox.setValue(hour) self.minuteBox.setValue(time.minute) self.secondBox.setValue(time.second) amPm = 'AM' if time.hour < 12 else 'PM' self.amPmBox.setValue(amPm) self.blockSignals(False) self.updateClock() def setDateFromText(self, text): """Set the date dialog from a string. Arguments: text -- the date in ISO format """ date = QDate.fromString(text, Qt.DateFormat.ISODate) if date.isValid(): self.calendar.setSelectedDate(date) def timeObject(self): """Return a datetime time object for the current dialog setting. """ hour = self.hourBox.value() if self.amPmBox.value == 'PM': if hour < 12: hour += 12 elif hour == 12: hour = 0 return datetime.time(hour, self.minuteBox.value(), self.secondBox.value()) def updateClock(self): """Update the clock based on the current time and focused widget. """ hands = [self.focusElem] if self.focusElem else [TimeElem.hour, TimeElem.minute, TimeElem.second] self.clock.setDisplay(self.timeObject(), hands) def handleFocusChange(self, elemType, isFocused): """Update clock based on focus changes. Arguments: elemType -- the TimeElem of the focus change isFocused -- True if focus is gained """ if isFocused: if elemType != self.focusElem: self.focusElem = elemType self.updateClock() elif elemType == self.focusElem: self.focusElem = None self.updateClock() def setFromClock(self, num): """Set the active spin box value from a clock click. Arguments: num -- the number clicked """ spinBox = getattr(self, self.focusElem.name + 'Box') spinBox.setValue(num) spinBox.selectAll() def signalUpdate(self): """Signal a time change and update the clock. """ self.updateClock() self.contentsChanged.emit() class TimeSpinBox(QSpinBox): """A spin box for time values with optional leading zero. """ focusChanged = pyqtSignal(TimeElem, bool) def __init__(self, elemType, minValue, maxValue, leadZero=True, parent=None): """Initialize the spin box. Arguments: elemType -- the TimeElem of this box minValue -- the minimum allowed value maxValue -- the maximum allowed value leadZero -- true if a leading zero used with single digit values parent -- the box's parent widget """ self.elemType = elemType self.leadZero = leadZero super().__init__(parent) self.setMinimum(minValue) self.setMaximum(maxValue) self.setWrapping(True) self.setAlignment(Qt.AlignmentFlag.AlignRight) def textFromValue(self, value): """Override to optionally add leading zero. Arguments: value -- the int value to convert """ if self.leadZero and value < 10: return '0' + repr(value) return repr(value) def focusInEvent(self, event): """Emit a signal when focused. Arguments: event -- the focus event """ super().focusInEvent(event) self.focusChanged.emit(self.elemType, True) def focusOutEvent(self, event): """Emit a signal if focus is lost. Arguments: event -- the focus event """ super().focusOutEvent(event) self.focusChanged.emit(self.elemType, False) class AmPmSpinBox(QAbstractSpinBox): """A spin box for AM/PM values. """ valueChanged = pyqtSignal() def __init__(self, parent=None): """Initialize the spin box. Arguments: parent -- the box's parent widget """ super().__init__(parent) self.value = 'AM' self.setDisplay() def stepBy(self, steps): """Step the spin box to the alternate value. Arguments: steps -- number of steps (ignored) """ self.value = 'PM' if self.value == 'AM' else 'AM' self.setDisplay() def stepEnabled(self): """Return enabled to show that stepping is always enabled. """ return (QAbstractSpinBox.StepEnabledFlag.StepUpEnabled | QAbstractSpinBox.StepEnabledFlag.StepDownEnabled) def setValue(self, value): """Set to text value if valid. Arguments: value -- the text value to set """ if value in ('AM', 'PM'): self.value = value self.setDisplay() def setDisplay(self): """Update display to match value. """ self.lineEdit().setText(self.value) self.valueChanged.emit() if self.hasFocus(): self.selectAll() def validate(self, inputStr, pos): """Check if the input string is acceptable. Arguments: inputStr -- the string to check pos -- the pos in the string (ignored) """ inputStr = inputStr.upper() if inputStr in ('AM', 'A'): self.value = 'AM' self.setDisplay() return (QValidator.State.Acceptable, 'AM', 2) if inputStr in ('PM', 'P'): self.value = 'PM' self.setDisplay() return (QValidator.State.Acceptable, 'PM', 2) return (QValidator.State.Invalid, 'xx', 2) def sizeHint(self): """Set prefered size. """ return super().sizeHint() + (QFontMetrics(self.font()). size(Qt.TextFlag.TextSingleLine, 'AM')) def focusInEvent(self, event): """Set select all when focused. Arguments: event -- the focus event """ super().focusInEvent(event) self.selectAll() def focusOutEvent(self, event): """Remove selection if focus is lost. Arguments: event -- the focus event """ super().focusOutEvent(event) self.lineEdit().deselect() class ClockWidget(QWidget): """A widget showing a clickable clock face. """ radius = 80 margin = 10 handLengths = {TimeElem.hour: int(radius * 0.5), TimeElem.minute: int(radius * 0.9), TimeElem.second: int(radius * 0.95)} handWidths = {TimeElem.hour: 7, TimeElem.minute: 5, TimeElem.second: 2} divisor = {TimeElem.hour: 120, TimeElem.minute: 10, TimeElem.second: 1 / 6} numClicked = pyqtSignal(int) def __init__(self, parent=None): """Initialize the clock. Arguments: parent -- the dialog's parent widget """ super().__init__(parent) self.time = datetime.time() self.hands = [] self.highlightAngle = None self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self.setMouseTracking(True) def setDisplay(self, time, hands): """Set the clock display. Arguments: time -- a datetime time value hands -- a list of TimeElem clock hands to show """ self.time = time self.hands = hands self.highlightAngle = None self.update() def paintEvent(self, event): """Paint the clock face. Arguments: event -- the paint event """ painter = QPainter(self) painter.save() painter.setBrush(QApplication.palette().base()) painter.setPen(Qt.PenStyle.NoPen) painter.drawEllipse(self.rect()) painter.translate(ClockWidget.radius + ClockWidget.margin, ClockWidget.radius + ClockWidget.margin) for timeElem in self.hands: painter.save() painter.setBrush(QApplication.palette().windowText()) painter.setPen(Qt.PenStyle.NoPen) seconds = (self.time.hour * 3600 + self.time.minute * 60 + self.time.second) angle = seconds / ClockWidget.divisor[timeElem] % 360 if len(self.hands) == 1: painter.setBrush(QApplication.palette().highlight()) if self.hands[0] == TimeElem.hour: angle = int(angle // 30 * 30) # truncate to whole hour else: angle = int(angle // 6 * 6) # truncate to whole min/sec painter.rotate(angle) points = (QPoint(0, -ClockWidget.handLengths[timeElem]), QPoint(ClockWidget.handWidths[timeElem], 8), QPoint(-ClockWidget.handWidths[timeElem], 8)) painter.drawConvexPolygon(*points) painter.restore() rect = QRect(0, 0, 20, 20) if len(self.hands) != 1 or self.hands[0] == TimeElem.hour: labels = [repr(num) for num in range(1, 13)] else: labels = ['{0:0>2}'.format(num) for num in range(5, 56, 5)] labels.append('00') for ang in range(30, 361, 30): rect.moveCenter(self.pointOnRadius(ang)) painter.setPen(QPen(QApplication.palette().text(), 1)) if len(self.hands) == 1 and (ang == angle or ang == self.highlightAngle): painter.setPen(QPen(QApplication.palette().highlight(), 1)) painter.drawText(rect, Qt.AlignmentFlag.AlignCenter, labels.pop(0)) painter.restore() super().paintEvent(event) def sizeHint(self): """Set prefered size. """ width = (ClockWidget.radius + ClockWidget.margin) * 2 return QSize(width, width) def pointOnRadius(self, angle): """Return a QPoint on the radius at the given angle. Arguments: angle -- the angle in dgrees from vertical (clockwise) """ angle = math.radians(angle) x = round(ClockWidget.radius * math.sin(angle)) y = 0 - round(ClockWidget.radius * math.cos(angle)) return QPoint(x, y) def pointToPosition(self, point): """Return a position (1 to 12) based on a screen point. Return None if not on a position. Arguments: point -- a QPoint screen position """ x = point.x() - ClockWidget.radius - ClockWidget.margin y = point.y() - ClockWidget.radius - ClockWidget.margin radius = math.sqrt(x**2 + y**2) if (ClockWidget.radius - 2 * ClockWidget.margin <= radius <= ClockWidget.radius + 2 * ClockWidget.margin): angle = math.degrees(math.atan2(-x, y)) + 180 if angle % 30 <= 10 or angle % 30 >= 20: pos = round(angle / 30) if pos == 0: pos = 12 return pos return None def mousePressEvent(self, event): """Signal user clicks on clock numbers if in single hand mode. Arguments: event -- the mouse press event """ if len(self.hands) == 1 and event.button() == Qt.MouseButton.LeftButton: pos = self.pointToPosition(event.position().toPoint()) if pos: if self.hands[0] != TimeElem.hour: if pos == 12: pos = 0 pos *= 5 self.numClicked.emit(pos) super().mousePressEvent(event) def mouseMoveEvent(self, event): """Highlight clickable numbers if in single hand mode. Arguments: event -- the mouse move event """ if len(self.hands) == 1: pos = self.pointToPosition(event.position().toPoint()) if pos: self.highlightAngle = pos * 30 self.update() elif self.highlightAngle != None: self.highlightAngle = None self.update() super().mouseMoveEvent(event) class DateTimeEditor(ComboEditor): """An editor widget for DateTimeFields. Uses a combo box with a clandar widget in place of the list popup. """ def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.dialog = None nowAction = QAction(_('Set to &Now'), self) nowAction.triggered.connect(self.setNow) self.lineEdit().extraMenuActions = [nowAction] def showPopup(self): """Override to show a popup entry widget in place of a list view. """ if not self.dialog: self.dialog = TimeDialog(True, self) self.dialog.contentsChanged.connect(self.setDateTime) self.dialog.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.dialog.width() + 1) screenBottom = QApplication.primaryScreen().availableGeometry().bottom() if pos.y() + self.dialog.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.dialog.height()) self.dialog.move(pos) try: storedText = self.fieldRef.storedText(self.currentText()) except ValueError: storedText = '' if storedText: dateText, timeText = storedText.split(' ', 1) self.dialog.setDateFromText(dateText) self.dialog.setTimeFromText(timeText) def hidePopup(self): """Override to hide the popup entry widget. """ if self.dialog: self.dialog.hide() super().hidePopup() def setDateTime(self): """Set the date and time based on a signal from the dialog calendar. """ if self.dialog: dateStr = self.dialog.calendar.selectedDate().toString(Qt.DateFormat.ISODate) timeStr = self.dialog.timeObject().isoformat() + '.000' self.setEditText(self.fieldRef.formatEditorText(dateStr + ' ' + timeStr)) def setNow(self): """Set to the current date and time. """ dateTime = QDateTime.currentDateTime() dateTimeStr = dateTime.toString('yyyy-MM-dd HH:mm:ss.zzz') self.setEditText(self.fieldRef.formatEditorText(dateTimeStr)) class ExtLinkEditor(ComboEditor): """An editor widget for external link fields. Uses a combo box with a link entry box in place of the list popup. """ dragLinkEnabled = True def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.setAcceptDrops(True) self.dialog = None openAction = QAction(_('&Open Link'), self) openAction.triggered.connect(self.openLink) folderAction = QAction(_('Open &Folder'), self) folderAction.triggered.connect(self.openFolder) self.lineEdit().extraMenuActions = [openAction, folderAction] self.lineEdit().contextMenuPrep.connect(self.updateActions) def showPopup(self): """Override to show a popup entry widget in place of a list view. """ if not self.dialog: self.dialog = ExtLinkDialog(True, self) self.dialog.contentsChanged.connect(self.setLink) self.dialog.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.dialog.width() + 1) screenBottom = QApplication.primaryScreen().availableGeometry().bottom() if pos.y() + self.dialog.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.dialog.height()) self.dialog.move(pos) self.dialog.setFromEditor(self.currentText()) def hidePopup(self): """Override to hide the popup entry widget. """ if self.dialog: self.dialog.hide() super().hidePopup() def setLink(self): """Set the current link from the popup dialog. """ self.setEditText(self.dialog.editorText()) def openLink(self): """Open the link in a web browser. """ text = self.currentText() if text: nameMatch = fieldformat.linkSeparateNameRegExp.match(text) if nameMatch: address = nameMatch.group(1).strip() else: address = text.strip() if address: if urltools.isRelative(address): defaultPath = globalref.mainControl.defaultPathObj(True) address = urltools.toAbsolute(address, str(defaultPath)) openExtUrl(address) def openFolder(self): """Open the link in a file manager/explorer. """ text = self.currentText() if text: nameMatch = fieldformat.linkSeparateNameRegExp.match(text) if nameMatch: address = nameMatch.group(1).strip() else: address = text.strip() if address and urltools.extractScheme(address) in ('', 'file'): if urltools.isRelative(address): defaultPath = globalref.mainControl.defaultPathObj(True) address = urltools.toAbsolute(address, str(defaultPath)) address = os.path.dirname(address) openExtUrl(address) def updateActions(self): """Set availability of custom context menu actions. """ address = self.currentText() if address: nameMatch = fieldformat.linkSeparateNameRegExp.match(address) if nameMatch: address = nameMatch.group(1).strip() else: address = address.strip() openAction, folderAction = self.lineEdit().extraMenuActions openAction.setEnabled(len(address) > 0) folderAction.setEnabled(len(address) > 0 and urltools.extractScheme(address) in ('', 'file')) def addDroppedUrl(self, urlText): """Add the URL link that was dropped on this editor from the view. Arguments: urlText -- the text of the link """ self.setEditText(urlText) def dragEnterEvent(self, event): """Accept drags of files to this widget. Arguments: event -- the drag event object """ if event.mimeData().hasUrls(): event.accept() def dropEvent(self, event): """Open a file dropped onto this widget. Arguments: event -- the drop event object """ fileList = event.mimeData().urls() if fileList: self.setEditText(fileList[0].toLocalFile()) _extLinkSchemes = ('http://', 'https://', 'mailto:', 'file://') _extLinkSchemeDict = {proto.split(':', 1)[0]: proto for proto in _extLinkSchemes} class ExtLinkDialog(QDialog): """A popup or normal dialog box for external link editing. """ contentsChanged = pyqtSignal() def __init__(self, popupDialog=False, parent=None): """Initialize the dialog widgets. Arguments: popupDialog -- add OK and cancel buttons if False parent -- the dialog's parent widget """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('External Link')) vertLayout = QVBoxLayout(self) vertLayout.setSpacing(1) schemeLabel = QLabel(_('Scheme')) vertLayout.addWidget(schemeLabel) schemeLayout = QHBoxLayout() vertLayout.addLayout(schemeLayout) schemeLayout.setSpacing(8) self.schemeButtons = QButtonGroup(self) self.schemeButtonDict = {} for scheme in _extLinkSchemes: scheme = scheme.split(':', 1)[0] button = QRadioButton(scheme) self.schemeButtons.addButton(button) self.schemeButtonDict[scheme] = button schemeLayout.addWidget(button) self.schemeButtonDict['http'].setChecked(True) self.schemeButtons.buttonClicked.connect(self.updateScheme) vertLayout.addSpacing(8) self.browseButton = QPushButton(_('&Browse for File')) self.browseButton.setAutoDefault(False) self.browseButton.clicked.connect(self.fileBrowse) vertLayout.addWidget(self.browseButton) vertLayout.addSpacing(8) self.pathTypeLabel = QLabel(_('File Path Type')) vertLayout.addWidget(self.pathTypeLabel) pathTypeLayout = QHBoxLayout() vertLayout.addLayout(pathTypeLayout) pathTypeLayout.setSpacing(8) pathTypeButtons = QButtonGroup(self) self.absoluteButton = QRadioButton(_('Absolute')) pathTypeButtons.addButton(self.absoluteButton) pathTypeLayout.addWidget(self.absoluteButton) self.relativeButton = QRadioButton(_('Relative')) pathTypeButtons.addButton(self.relativeButton) pathTypeLayout.addWidget(self.relativeButton) self.absoluteButton.setChecked(True) pathTypeButtons.buttonClicked.connect(self.updatePathType) vertLayout.addSpacing(8) addressLabel = QLabel(_('Address')) vertLayout.addWidget(addressLabel) self.addressEdit = QLineEdit() self.addressEdit.textEdited.connect(self.checkAddress) vertLayout.addWidget(self.addressEdit) vertLayout.addSpacing(8) nameLabel = QLabel(_('Display Name')) vertLayout.addWidget(nameLabel) self.nameEdit = QLineEdit() self.nameEdit.textEdited.connect(self.contentsChanged) vertLayout.addWidget(self.nameEdit) if popupDialog: self.setWindowFlags(Qt.WindowType.Popup) else: vertLayout.addSpacing(8) ctrlLayout = QHBoxLayout() vertLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.addressEdit.setFocus() def setFromEditor(self, editorText): """Set the dialog contents from a string in editor format. Arguments: editorText -- string in "link [name]" format """ name = address = '' editorText = editorText.strip() if editorText: nameMatch = fieldformat.linkSeparateNameRegExp.match(editorText) if nameMatch: address, name = nameMatch.groups() address = address.strip() else: address = editorText name = urltools.shortName(address) self.setFromComponents(address, name) def setFromComponents(self, address, name): """Set the dialog contents from separate address and name. Arguments: address -- the link address, including the scheme prefix name -- the displayed name for the link """ scheme = urltools.extractScheme(address) if scheme not in _extLinkSchemeDict: if not scheme: address = urltools.replaceScheme('file', address) scheme = 'file' self.schemeButtonDict[scheme].setChecked(True) if address and urltools.isRelative(address): self.relativeButton.setChecked(True) else: self.absoluteButton.setChecked(True) self.addressEdit.setText(address) self.nameEdit.setText(name) self.updateFileControls() def editorText(self): """Return the dialog contents in data editor format ("link [name]"). """ address = self.currentAddress() if not address: return '' name = self.nameEdit.text().strip() if not name: name = urltools.shortName(address) return '{0} [{1}]'.format(address, name) def htmlText(self): """Return the dialog contents in HTML link format. """ address = self.currentAddress() if not address: return '' name = self.nameEdit.text().strip() if not name: name = urltools.shortName(address) return '{1}'.format(address, name) def currentAddress(self): """Return current address with the selected scheme prefix. """ scheme = self.schemeButtons.checkedButton().text() address = self.addressEdit.text().strip() return urltools.replaceScheme(scheme, address) def checkAddress(self): """Update controls based on a change to the address field. Makes minimum changes to scheme and absolute controls, since the address may be incomplete. """ address = self.addressEdit.text().strip() scheme = urltools.extractScheme(address) if scheme in _extLinkSchemeDict: self.schemeButtonDict[scheme].setChecked(True) if scheme != 'file': self.absoluteButton.setChecked(True) self.updateFileControls() self.contentsChanged.emit() def updateScheme(self): """Update scheme in the address due to scheme button change. """ scheme = self.schemeButtons.checkedButton().text() address = self.addressEdit.text().strip() address = urltools.replaceScheme(scheme, address) self.addressEdit.setText(address) if urltools.isRelative(address): self.relativeButton.setChecked(True) else: self.absoluteButton.setChecked(True) self.updateFileControls() self.contentsChanged.emit() def updatePathType(self): """Update file path based on a change in the absolute/relative control. """ absolute = self.absoluteButton.isChecked() defaultPath = globalref.mainControl.defaultPathObj(True) address = self.addressEdit.text().strip() if absolute: address = urltools.toAbsolute(address, str(defaultPath)) else: address = urltools.toRelative(address, str(defaultPath)) self.addressEdit.setText(address) self.contentsChanged.emit() def updateFileControls(self): """Set file browse & type controls available based on current scheme. """ enable = self.schemeButtons.checkedButton().text() == 'file' self.browseButton.setEnabled(enable) self.pathTypeLabel.setEnabled(enable) self.absoluteButton.setEnabled(enable) self.relativeButton.setEnabled(enable) def fileBrowse(self): """Show dialog to browse for a file to be linked. Adjust based on absolute or relative path settings. """ refPath = str(globalref.mainControl.defaultPathObj(True)) defaultPath = refPath oldAddress = self.addressEdit.text().strip() oldScheme = urltools.extractScheme(oldAddress) if oldAddress and not oldScheme or oldScheme == 'file': if urltools.isRelative(oldAddress): oldAddress = urltools.toAbsolute(oldAddress, refPath) oldAddress = urltools.extractAddress(oldAddress) if os.access(oldAddress, os.F_OK): defaultPath = oldAddress address, selFltr = QFileDialog.getOpenFileName(QApplication. activeWindow(), _('TreeLine - External Link File'), defaultPath, globalref.fileFilters['all']) if address: if self.relativeButton.isChecked(): address = urltools.toRelative(address, refPath) self.setFromComponents(address, urltools.shortName(address)) self.show() self.contentsChanged.emit() class IntLinkEditor(ComboEditor): """An editor widget for internal link fields. Uses a combo box with a link select dialog in place of the list popup. """ inLinkSelectMode = pyqtSignal(bool) def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.address = '' self.intLinkDialog = None self.setLineEdit(PartialLineEditor(self)) openAction = QAction(_('&Go to Target'), self) openAction.triggered.connect(self.openLink) clearAction = QAction(_('Clear &Link'), self) clearAction.triggered.connect(self.clearLink) self.lineEdit().extraMenuActions = [openAction, clearAction] def setContents(self, text): """Set the contents of the editor to text. Arguments: text - the new text contents for the editor """ super().setContents(text) if not text: self.lineEdit().staticLength = 0 self.address = '' return try: self.address, name = self.fieldRef.addressAndName(self.nodeRef. data.get(self.fieldRef.name, '')) except ValueError: self.address = '' self.address = self.address.lstrip('#') nameMatch = fieldformat.linkSeparateNameRegExp.match(text) if nameMatch: link = nameMatch.group(1) self.lineEdit().staticLength = len(link) + 1 else: self.lineEdit().staticLength = 0 def contents(self): """Return the editor contents in "address [name]" format. """ if not self.address: return self.currentText() nameMatch = fieldformat.linkSeparateNameRegExp.match(self. currentText()) if nameMatch: name = nameMatch.group(2) else: name = '' return '{0} [{1}]'.format(self.address, name.strip()) def clearLink(self): """Clear the contents of the editor. """ self.setContents('') self.signalUpdate() def showPopup(self): """Override to show a popup entry widget in place of a list view. """ if not self.intLinkDialog: self.intLinkDialog = IntLinkDialog(True, self) self.intLinkDialog.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.intLinkDialog.width() + 1) screenBottom = (QApplication.primaryScreen().availableGeometry(). bottom()) if pos.y() + self.intLinkDialog.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.intLinkDialog.height()) self.intLinkDialog.move(pos) self.inLinkSelectMode.emit(True) def hidePopup(self): """Override to hide the popup entry widget. """ if self.intLinkDialog: self.intLinkDialog.hide() self.inLinkSelectMode.emit(False) super().hidePopup() def setLinkFromNode(self, node): """Set the current link from a clicked node. Arguments: node -- the node to set the unique ID from """ self.hidePopup() self.address = node.uId linkTitle = node.title() nameMatch = fieldformat.linkSeparateNameRegExp.match(self. currentText()) if nameMatch: name = nameMatch.group(2) else: name = linkTitle self.setEditText('LinkTo: {0} [{1}]'.format(linkTitle, name)) self.lineEdit().staticLength = len(linkTitle) + 9 def openLink(self): """Open the link in a web browser. """ if self.address: editView = self.parent().parent() editView.treeView.selectionModel().selectNodeById(self.address) def setCursorPoint(self, point): """Set the cursor to the given point. Arguments: point -- the QPoint for the new cursor position """ self.lineEdit().setCursorPoint(point) self.lineEdit().fixSelection() class PartialLineEditor(LineEditor): """A line used in internal link combo editors. Only allows the name portion to be selected or editd. """ def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent, True) self.staticLength = 0 def fixSelection(self): """Fix the selection and cursor to not include static portion of text. """ cursorPos = self.cursorPosition() if -1 < self.selectionStart() < self.staticLength: endPos = self.selectionStart() + len(self.selectedText()) if endPos > self.staticLength: if cursorPos >= self.staticLength: self.setSelection(self.staticLength, endPos - self.staticLength) else: # reverse select to get cursor at selection start self.setSelection(endPos, self.staticLength - endPos) return self.deselect() if cursorPos < self.staticLength: self.setCursorPosition(self.staticLength) def selectAll(self): """Select all editable text. """ self.setSelection(self.staticLength, len(self.text())) def mouseReleaseEvent(self, event): """Fix selection if required after mouse release. Arguments: event -- the mouse release event """ super().mouseReleaseEvent(event) self.fixSelection() def keyPressEvent(self, event): """Avoid edits or cursor movements to the static portion of the text. Arguments: event -- the mouse release event """ if (event.key() == Qt.Key.Key_Backspace and (self.cursorPosition() <= self.staticLength and not self.hasSelectedText())): return if event.key() in (Qt.Key.Key_Left, Qt.Key.Key_Home): super().keyPressEvent(event) self.fixSelection() return super().keyPressEvent(event) class IntLinkDialog(QDialog): """A popup dialog box for internal link editing. """ contentsChanged = pyqtSignal() def __init__(self, popupDialog=False, parent=None): """Initialize the dialog widgets. Arguments: popupDialog -- add OK and cancel buttons if False parent -- the dialog's parent widget """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.FramelessWindowHint) layout = QVBoxLayout(self) label = QLabel(_('(Click link target in tree)')) layout.addWidget(label) class EmbedIntLinkDialog(QDialog): """A popup or normal dialog box for internal link editing. """ contentsChanged = pyqtSignal() targetClickDialogRef = None def __init__(self, structRef, parent=None): """Initialize the dialog widgets. Arguments: structRef -- a ref to the tree structure parent -- the dialog's parent widget """ super().__init__(parent) self.structRef = structRef self.address = '' self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Internal Link')) vertLayout = QVBoxLayout(self) vertLayout.setSpacing(1) self.linkLabel = QLabel() vertLayout.addWidget(self.linkLabel) infoLabel = QLabel(_('(Click link target in tree)')) vertLayout.addWidget(infoLabel) vertLayout.addSpacing(8) nameLabel = QLabel(_('Display Name')) vertLayout.addWidget(nameLabel) self.nameEdit = QLineEdit() self.nameEdit.textEdited.connect(self.contentsChanged) vertLayout.addWidget(self.nameEdit) vertLayout.addSpacing(8) ctrlLayout = QHBoxLayout() vertLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) self.okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(self.okButton) self.okButton.setDefault(True) self.okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) def updateLinkText(self): """Update the link label using the current address. """ title = '' name = self.nameEdit.text().strip() if self.address: targetNode = self.structRef.nodeDict.get(self.address, None) if targetNode: title = targetNode.title() if not name: self.nameEdit.setText(title) self.linkLabel.setText('LinkTo: {0}'.format(title)) self.okButton.setEnabled(len(self.address) > 0) def setFromNode(self, node): """Set the dialog contents from a clicked node. Arguments: node -- the node to set the unique ID from """ self.address = node.uId self.updateLinkText() def setFromComponents(self, address, name): """Set the dialog contents from separate address and name. Arguments: address -- the link address, including the protocol prefix name -- the displayed name for the link """ self.address = address self.nameEdit.setText(name) self.updateLinkText() def htmlText(self): """Return the dialog contents in HTML link format. """ name = self.nameEdit.text().strip() if not name: name = _('link') return '{1}'.format(self.address, name) class PictureLinkEditor(ComboEditor): """An editor widget for picture link fields. Uses a combo box with a link entry box in place of the list popup. """ dragLinkEnabled = True def __init__(self, parent=None): """Initialize the editor class. Arguments: parent -- the parent, if given """ super().__init__(parent) self.dialog = None openAction = QAction(_('&Open Picture'), self) openAction.triggered.connect(self.openPicture) self.lineEdit().extraMenuActions = [openAction] def showPopup(self): """Override to show a popup entry widget in place of a list view. """ if not self.dialog: self.dialog = PictureLinkDialog(True, self) self.dialog.contentsChanged.connect(self.setLink) self.dialog.show() pos = self.mapToGlobal(self.rect().bottomRight()) pos.setX(pos.x() - self.dialog.width() + 1) screenBottom = (QApplication.primaryScreen().availableGeometry(). bottom()) if pos.y() + self.dialog.height() > screenBottom: pos.setY(pos.y() - self.rect().height() - self.dialog.height()) self.dialog.move(pos) self.dialog.setAddress(self.currentText()) def hidePopup(self): """Override to hide the popup entry widget. """ if self.dialog: self.dialog.hide() super().hidePopup() def setLink(self): """Set the current link from the popup dialog. """ self.setEditText(self.dialog.currentAddress()) def openPicture(self): """Open the link in a web browser. """ address = self.currentText() if address: if urltools.isRelative(address): defaultPath = globalref.mainControl.defaultPathObj(True) address = urltools.toAbsolute(address, str(defaultPath)) openExtUrl(address) def addDroppedUrl(self, urlText): """Add the URL link that was dropped on this editor from the view. Arguments: urlText -- the text of the link """ self.setEditText(urlText) class PictureLinkDialog(QDialog): """A popup or normal dialog box for picture link editing. """ thumbnailSize = QSize(250, 100) contentsChanged = pyqtSignal() def __init__(self, popupDialog=False, parent=None): """Initialize the dialog widgets. Arguments: popupDialog -- add OK and cancel buttons if False parent -- the dialog's parent widget """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Picture Link')) self.setMinimumWidth(self.thumbnailSize.width()) vertLayout = QVBoxLayout(self) vertLayout.setSpacing(1) self.thumbnail = QLabel() pixmap = QPixmap(self.thumbnailSize) pixmap.fill() self.thumbnail.setPixmap(pixmap) vertLayout.addWidget(self.thumbnail, 0, Qt.AlignmentFlag.AlignHCenter) vertLayout.addSpacing(8) self.browseButton = QPushButton(_('&Browse for File')) self.browseButton.setAutoDefault(False) self.browseButton.clicked.connect(self.fileBrowse) vertLayout.addWidget(self.browseButton) vertLayout.addSpacing(8) self.pathTypeLabel = QLabel(_('File Path Type')) vertLayout.addWidget(self.pathTypeLabel) pathTypeLayout = QHBoxLayout() vertLayout.addLayout(pathTypeLayout) pathTypeLayout.setSpacing(8) pathTypeButtons = QButtonGroup(self) self.absoluteButton = QRadioButton(_('Absolute')) pathTypeButtons.addButton(self.absoluteButton) pathTypeLayout.addWidget(self.absoluteButton) self.relativeButton = QRadioButton(_('Relative')) pathTypeButtons.addButton(self.relativeButton) pathTypeLayout.addWidget(self.relativeButton) self.absoluteButton.setChecked(True) pathTypeButtons.buttonClicked.connect(self.updatePathType) vertLayout.addSpacing(8) addressLabel = QLabel(_('Address')) vertLayout.addWidget(addressLabel) self.addressEdit = QLineEdit() self.addressEdit.textEdited.connect(self.checkAddress) vertLayout.addWidget(self.addressEdit) vertLayout.addSpacing(8) if popupDialog: self.setWindowFlags(Qt.WindowType.Popup) else: vertLayout.addSpacing(8) ctrlLayout = QHBoxLayout() vertLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.addressEdit.setFocus() def setAddress(self, address): """Set the dialog contents from a string in editor format. Arguments: address -- URL string for the address """ if address and urltools.isRelative(address): self.relativeButton.setChecked(True) else: self.absoluteButton.setChecked(True) self.addressEdit.setText(address) self.updateThumbnail() def setFromHtml(self, htmlStr): """Set the dialog contents from an HTML link. Arguments: htmlStr -- string in HTML link format """ linkMatch = imageRegExp.search(htmlStr) if linkMatch: address = linkMatch.group(1) self.setAddress(address.strip()) def htmlText(self): """Return the dialog contents in HTML link format. """ address = self.currentAddress() if not address: return '' return ''.format(address) def currentAddress(self): """Return current address with the selected scheme prefix. """ return self.addressEdit.text().strip() def checkAddress(self): """Update absolute controls based on a change to the address field. """ address = self.addressEdit.text().strip() if address: if urltools.isRelative(address): self.relativeButton.setChecked(True) else: self.absoluteButton.setChecked(True) self.updateThumbnail() self.contentsChanged.emit() def updatePathType(self): """Update path based on a change in the absolute/relative control. """ absolute = self.absoluteButton.isChecked() defaultPath = globalref.mainControl.defaultPathObj(True) address = self.addressEdit.text().strip() if absolute: address = urltools.toAbsolute(address, str(defaultPath), False) else: address = urltools.toRelative(address, str(defaultPath)) self.addressEdit.setText(address) self.updateThumbnail() self.contentsChanged.emit() def updateThumbnail(self): """Update the thumbnail with an image from the current address. """ address = self.addressEdit.text().strip() if urltools.isRelative(address): refPath = str(globalref.mainControl.defaultPathObj(True)) address = urltools.toAbsolute(address, refPath, False) pixmap = QPixmap(address) if pixmap.isNull(): pixmap = QPixmap(self.thumbnailSize) pixmap.fill() else: pixmap = pixmap.scaled(self.thumbnailSize, Qt.AspectRatioMode.KeepAspectRatio) self.thumbnail.setPixmap(pixmap) def fileBrowse(self): """Show dialog to browse for a file to be linked. Adjust based on absolute or relative path settings. """ refPath = str(globalref.mainControl.defaultPathObj(True)) defaultPath = refPath oldAddress = self.addressEdit.text().strip() if oldAddress: if urltools.isRelative(oldAddress): oldAddress = urltools.toAbsolute(oldAddress, refPath) oldAddress = urltools.extractAddress(oldAddress) if os.access(oldAddress, os.F_OK): defaultPath = oldAddress address, selFltr = QFileDialog.getOpenFileName(QApplication. activeWindow(), _('TreeLine - Picture File'), defaultPath, globalref.fileFilters['all']) if address: if self.relativeButton.isChecked(): address = urltools.toRelative(address, refPath) self.setAddress(address) self.updateThumbnail() self.show() self.contentsChanged.emit() #### Utility Functions #### def openExtUrl(path): """Open a web browser or a application for a directory or file. Arguments: path -- the path to open """ if sys.platform.startswith('win'): os.startfile(path) elif sys.platform.startswith('darwin'): subprocess.call(['open', path]) else: subprocess.call(['xdg-open', path]) TreeLine-3.2.1/source/dataeditview.py000066400000000000000000001070051506556630100175620ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # dataeditview.py, provides a class for the data edit right-hand view # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** from PyQt6.QtCore import QEvent, QPointF, QRectF, QSize, Qt, pyqtSignal from PyQt6.QtGui import (QKeySequence, QPainterPath, QPalette, QPen, QSyntaxHighlighter, QTextCharFormat, QTextCursor, QTextDocument) from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QStyledItemDelegate, QTableWidget, QTableWidgetItem) import treenode import undo import urltools import dataeditors import globalref _minColumnWidth = 80 defaultFont = None class DataEditCell(QTableWidgetItem): """Class override for data edit view cells. Used for the cells with editable content. """ def __init__(self, spot, field, titleCellRef, typeCellRef): """Initialize the editable cells in the data edit view. Arguments: spot -- the spot referenced by this cell field -- the field object referenced by this cell titleCellRef -- the title cell to update based on data changes typeCellRef -- the format type cell to update based on type changes """ super().__init__() self.spot = spot self.node = spot.nodeRef self.field = field self.titleCellRef = titleCellRef self.typeCellRef = typeCellRef self.errorFlag = False self.cursorPos = (-1, -1) self.scrollPos = -1 # store doc to speed up delegate sizeHint and paint calls self.doc = QTextDocument() self.doc.setDefaultFont(defaultFont) self.doc.setDocumentMargin(6) self.updateText() def updateText(self): """Update the text based on the current node data. """ self.errorFlag = False try: self.setText(self.field.editorText(self.node)) except ValueError as err: if len(err.args) >= 2: self.setText(err.args[1]) else: self.setText(self.node.data.get(self.field.name, '')) self.errorFlag = True if self.field.showRichTextInCell: self.doc.setHtml(self.text()) else: self.doc.setPlainText(self.text()) def storeEditorState(self, editor): """Store the cursor & scroll positions baseed on an editor signal. Arguments: editor -- the editor that will get its state saved """ self.cursorPos = editor.cursorPosTuple() self.scrollPos = editor.scrollPosition() class DataEditDelegate(QStyledItemDelegate): """Class override for display and editing of DataEditCells. """ def __init__(self, parent=None): """Initialize the delegate class. Arguments: parent -- the parent view """ super().__init__(parent) self.editorClickPos = None self.tallEditScrollPos = -1 self.lastEditor = None self.prevNumLines = -1 def paint(self, painter, styleOption, modelIndex): """Paint the Data Edit Cells with support for rich text. Other cells are painted with the base class default. Also paints an error rectangle if the format error flag is set. Arguments: painter -- the painter instance styleOption -- the data for styles and geometry modelIndex -- the index of the cell to be painted """ cell = self.parent().item(modelIndex.row(), modelIndex.column()) if isinstance(cell, DataEditCell): painter.save() doc = cell.doc doc.setTextWidth(styleOption.rect.width()) painter.translate(styleOption.rect.topLeft()) paintRect = QRectF(0, 0, styleOption.rect.width(), styleOption.rect.height()) painter.setClipRect(paintRect) painter.fillRect(paintRect, QApplication.palette().base()) painter.setPen(QPen(QApplication.palette().text(), 1)) painter.drawRect(paintRect.adjusted(0, 0, -1, -1)) doc.drawContents(painter) if cell.errorFlag: path = QPainterPath(QPointF(0, 0)) path.lineTo(0, 10) path.lineTo(10, 0) path.closeSubpath() painter.fillPath(path, QApplication.palette().highlight()) painter.restore() else: super().paint(painter, styleOption, modelIndex) def sizeHint(self, styleOption, modelIndex): """Return the size of Data Edit Cells with rich text. Other cells return the base class size. Arguments: styleOption -- the data for styles and geometry modelIndex -- the index of the cell to be painted """ cell = self.parent().item(modelIndex.row(), modelIndex.column()) if isinstance(cell, DataEditCell): doc = cell.doc doc.setTextWidth(styleOption.rect.width()) size = doc.documentLayout().documentSize().toSize() maxHeight = self.parent().height() * 9 // 10 # 90% of view height if (size.height() > maxHeight and globalref.genOptions['EditorLimitHeight']): size.setHeight(maxHeight) if cell.field.numLines > 1: minDoc = QTextDocument('\n' * (cell.field.numLines - 1)) minDoc.setDefaultFont(cell.doc.defaultFont()) minHeight = (minDoc.documentLayout().documentSize().toSize(). height()) if minHeight > size.height(): size.setHeight(minHeight) return size + QSize(0, 4) return super().sizeHint(styleOption, modelIndex) def createEditor(self, parent, styleOption, modelIndex): """Return a new text editor for a cell. Arguments: parent -- the parent widget for the editor styleOption -- the data for styles and geometry modelIndex -- the index of the cell to be edited """ cell = self.parent().item(modelIndex.row(), modelIndex.column()) if isinstance(cell, DataEditCell): editor = getattr(dataeditors, cell.field.editorClassName)(parent) editor.setFont(cell.doc.defaultFont()) if hasattr(editor, 'fieldRef'): editor.fieldRef = cell.field if hasattr(editor, 'nodeRef'): editor.nodeRef = cell.node if cell.errorFlag: editor.setErrorFlag() # self.parent().setFocusProxy(editor) editor.contentsChanged.connect(self.commitData) editor.editEnding.connect(cell.storeEditorState) if (not globalref.genOptions['EditorLimitHeight'] and hasattr(editor, 'keyPressed')): editor.keyPressed.connect(self.scrollOnKeyPress) if hasattr(editor, 'inLinkSelectMode'): editor.inLinkSelectMode.connect(self.parent(). changeInLinkSelectMode) if hasattr(editor, 'setLinkFromNode'): self.parent().internalLinkSelected.connect(editor. setLinkFromNode) # viewport filter required to catch editor events try: editor.viewport().installEventFilter(self) except AttributeError: try: editor.lineEdit().installEventFilter(self) except AttributeError: pass self.lastEditor = editor editor.setFocus() return editor return super().createEditor(parent, styleOption, modelIndex) def setEditorData(self, editor, modelIndex): """Sets the text to be edited by the editor item. Arguments: editor -- the editor widget modelIndex -- the index of the cell to being edited """ cell = self.parent().item(modelIndex.row(), modelIndex.column()) if isinstance(cell, DataEditCell): try: # set from data to pick up any background changes editor.setContents(cell.field.editorText(cell.node)) except ValueError: # if data bad, just set it like the cell editor.setContents(modelIndex.data()) if cell.errorFlag: editor.setErrorFlag() editor.show() if self.editorClickPos: editor.setCursorPoint(self.editorClickPos) self.editorClickPos = None elif globalref.genOptions['EditorLimitHeight']: if cell.cursorPos[1] >= 0: editor.setCursorPos(*cell.cursorPos) cell.cursorPos = (-1, -1) if cell.scrollPos >= 0: editor.setScrollPosition(cell.scrollPos) cell.scrollPos = -1 else: editor.resetCursor() if (not globalref.genOptions['EditorLimitHeight'] and globalref.genOptions['EditorOnHover'] and self.tallEditScrollPos >= 0): # maintain scroll position for unlimited height editors # when hovering (use adjustScroll() for non-hovering self.parent().verticalScrollBar().setValue(self. tallEditScrollPos) else: super().setEditorData(editor, modelIndex) def setModelData(self, editor, styleOption, modelIndex): """Update the model with the results from an editor. Sets the cell error flag if the format doesn't match. Arguments: editor -- the editor widget styleOption -- the data for styles and geometry modelIndex -- the index of the cell to be painted """ cell = self.parent().item(modelIndex.row(), modelIndex.column()) if isinstance(cell, DataEditCell): if editor.modified: newText = editor.contents() numLines = newText.count('\n') skipUndoAvail = numLines == self.prevNumLines self.prevNumLines = numLines treeStructure = globalref.mainControl.activeControl.structure undo.DataUndo(treeStructure.undoList, cell.node, False, False, skipUndoAvail, cell.field.name) try: cell.node.setData(cell.field, newText) except ValueError: editor.setErrorFlag() self.parent().nodeModified.emit(cell.node) cell.titleCellRef.setText(cell.node.title(cell.spot)) cell.typeCellRef.setText(cell.node.formatRef.name) editor.modified = False else: super().setModelData(editor, styleOption, modelIndex) def updateEditorGeometry(self, editor, styleOption, modelIndex): """Update the editor geometry to match the cell. Arguments: editor -- the editor widget styleOption -- the data for styles and geometry modelIndex -- the index of the cell to be painted """ editor.setMaximumSize(self.sizeHint(styleOption, modelIndex)) super().updateEditorGeometry(editor, styleOption, modelIndex) def adjustScroll(self): """Reset the scroll back to the original for unlimited height editors. Called from signal after any scroll change. Needed for non-hovering to fix late scroll reset after editor created. """ if (not globalref.genOptions['EditorLimitHeight'] and not globalref.genOptions['EditorOnHover'] and self.tallEditScrollPos >= 0): self.parent().verticalScrollBar().setValue(self.tallEditScrollPos) self.tallEditScrollPos = -1 def scrollOnKeyPress(self, editor): """Adjust the scroll position to make cursor visible. Needed after key presses on unlimited height editors. Arguments: editor -- the editor with the key press """ if not globalref.genOptions['EditorLimitHeight']: view = self.parent() cursorRect = editor.cursorRect() upperPos = editor.mapToGlobal(cursorRect.topLeft()).y() lowerPos = editor.mapToGlobal(cursorRect.bottomLeft()).y() viewRect = view.viewport().rect() viewTop = view.mapToGlobal(viewRect.topLeft()).y() viewBottom = view.mapToGlobal(viewRect.bottomLeft()).y() bar = view.verticalScrollBar() if upperPos < viewTop: bar.setValue(bar.value() - (viewTop - upperPos)) elif lowerPos > viewBottom: bar.setValue(bar.value() + (lowerPos - viewBottom)) def editorEvent(self, event, model, styleOption, modelIndex): """Save the mouse click position in order to set the editor's cursor. Arguments: event -- the mouse click event model -- the model (not used) styleOption -- the data for styles and geometry (not used) modelIndex -- the index of the cell (not used) """ if event.type() == QEvent.Type.MouseButtonPress: self.editorClickPos = event.globalPosition().toPoint() # save scroll position for clicks on unlimited height editors self.tallEditScrollPos = self.parent().verticalScrollBar().value() return super().editorEvent(event, model, styleOption, modelIndex) def eventFilter(self, editor, event): """Override to handle various focus changes and control keys. Navigate away from this view if tab hit on end items. Catches tab before QDelegate's event filter on the editor. Also closes the editor if focus is lost for certain reasons. Arguments: editor -- the editor that Qt installed a filter on event -- the key press event """ if event.type() == QEvent.Type.KeyPress: view = self.parent() if (event.key() == Qt.Key.Key_Tab and view.currentRow() == view.rowCount() - 1): view.focusOtherView.emit(True) return True if (event.key() == Qt.Key.Key_Backtab and view.currentRow() == 1): view.focusOtherView.emit(False) return True if (event.modifiers() == Qt.KeyboardModifier.ControlModifier and Qt.Key.Key_A <= event.key() <= Qt.Key.Key_Z): key = QKeySequence(event.keyCombination()) view.shortcutEntered.emit(key) return True if event.type() == QEvent.Type.MouseButtonPress: self.prevNumLines = -1 # reset undo avail for mouse cursor changes if event.type() == QEvent.Type.FocusOut: self.prevNumLines = -1 # reset undo avail for any focus loss if (event.reason() in (Qt.FocusReason.MouseFocusReason, Qt.FocusReason.TabFocusReason, Qt.FocusReason.BacktabFocusReason) and (not hasattr(editor, 'calendar') or not editor.calendar or not editor.calendar.isVisible()) and (not hasattr(editor, 'intLinkDialog') or not editor.intLinkDialog or not editor.intLinkDialog.isVisible())): self.parent().endEditor() return True return super().eventFilter(editor, event) class DataEditView(QTableWidget): """Class override for the table-based data edit view. Sets view defaults and updates the content. """ nodeModified = pyqtSignal(treenode.TreeNode) inLinkSelectMode = pyqtSignal(bool) internalLinkSelected = pyqtSignal(treenode.TreeNode) focusOtherView = pyqtSignal(bool) hoverFocusActive = pyqtSignal() shortcutEntered = pyqtSignal(QKeySequence) def __init__(self, treeView, allActions, isChildView=True, parent=None): """Initialize the data edit view default view settings. Arguments: treeView - the tree view, needed for the current selection model allActions -- a dict containing actions for the editor context menu isChildView -- shows selected nodes if false, child nodes if true parent -- the parent main window """ super().__init__(0, 2, parent) self.treeView = treeView self.allActions = allActions self.isChildView = isChildView self.hideChildView = not globalref.genOptions['InitShowChildPane'] self.prevHoverCell = None self.inLinkSelectActive = False self.setAcceptDrops(True) self.setMouseTracking(globalref.genOptions['EditorOnHover']) self.horizontalHeader().hide() self.verticalHeader().hide() self.setVerticalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel) self.setHorizontalScrollMode(QAbstractItemView.ScrollMode. ScrollPerPixel) self.verticalScrollBar().setSingleStep(self.fontMetrics(). lineSpacing()) self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.setItemDelegate(DataEditDelegate(self)) self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.setShowGrid(False) pal = self.palette() pal.setBrush(QPalette.ColorRole.Base, QApplication.palette().window()) pal.setBrush(QPalette.ColorRole.Text, QApplication.palette().windowText()) self.setPalette(pal) self.currentItemChanged.connect(self.moveEditor) self.verticalScrollBar().valueChanged.connect(self.itemDelegate(). adjustScroll) def updateContents(self): """Reload the view's content if the view is shown. Avoids update if view is not visible or has zero height or width. """ selSpots = self.treeView.selectionModel().selectedSpots() if self.isChildView: if (len(selSpots) > 1 or self.hideChildView or (selSpots and not selSpots[0].nodeRef.childList)): self.hide() return if not selSpots: # use top node childList from tree structure selSpots = [globalref.mainControl.activeControl.structure. structSpot()] elif not selSpots: self.hide() return self.show() if not self.isVisible() or self.height() == 0 or self.width() == 0: return if self.isChildView: selSpots = selSpots[0].childSpots() self.clear() if selSpots: self.hide() # 2nd update very slow if shown during update self.setRowCount(100000) rowNum = -2 for spot in selSpots: rowNum = self.addNodeData(spot, rowNum + 2) self.setRowCount(rowNum + 1) self.adjustSizes() self.scrollToTop() self.show() def addNodeData(self, spot, startRow): """Populate the view with the data from the given node. Returns the last row number used. Arguments: spot -- the spot to add startRow -- the row offset """ node = spot.nodeRef formatName = node.formatRef.name typeCell = self.createInactiveCell(formatName) self.setItem(startRow, 0, typeCell) titleCell = self.createInactiveCell(node.title(spot)) self.setItem(startRow, 1, titleCell) fields = node.formatRef.fields() if not globalref.genOptions['EditNumbering']: fields = [field for field in fields if field.typeName != 'Numbering'] if not globalref.genOptions['ShowMath']: fields = [field for field in fields if field.typeName != 'Math'] row = 0 # initialize for cases with only Numbering or Math fields for row, field in enumerate(fields, startRow + 1): self.setItem(row, 0, self.createInactiveCell(field.name, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)) self.setItem(row, 1, DataEditCell(spot, field, titleCell, typeCell)) self.setItem(row + 1, 0, self.createInactiveCell('')) self.setItem(row + 1, 1, self.createInactiveCell('')) return row def updateUnselectedCells(self): """Refresh the data in active cells, keeping the cell structure. """ if not self.isVisible() or self.height() == 0 or self.width() == 0: return selSpots = self.treeView.selectionModel().selectedSpots() if self.isChildView: if not selSpots: # use top node childList from tree structure selSpots = [globalref.mainControl.activeControl.structure. structSpot()] selSpots = selSpots[0].childSpots() elif not selSpots: return rowNum = -2 for spot in selSpots: rowNum = self.refreshNodeData(spot, rowNum + 2) def refreshNodeData(self, spot, startRow): """Refresh the data in active cells for this node. Returns the last row number used. Arguments: node -- the node to add startRow -- the row offset """ node = spot.nodeRef self.item(startRow, 1).setText(node.title(spot)) fields = node.formatRef.fields() if not globalref.genOptions['EditNumbering']: fields = [field for field in fields if field.typeName != 'Numbering'] if not globalref.genOptions['ShowMath']: fields = [field for field in fields if field.typeName != 'Math'] for row, field in enumerate(fields, startRow + 1): cell = self.item(row, 1) if not cell.isSelected(): cell.updateText() return row @staticmethod def createInactiveCell(text, alignment=None): """Return a new inactive data edit view cell. Arguments: text -- the initial text string for the cell alignment -- the text alignment QT constant (None for default) """ cell = QTableWidgetItem(text) cell.setFlags(Qt.ItemFlag.NoItemFlags) if alignment: cell.setTextAlignment(alignment) return cell def moveEditor(self, newCell, prevCell): """Close old editor and open new one based on new current cell. Arguments: newCell -- the new current edit cell item prevCell - the old current cell item """ try: if prevCell and hasattr(prevCell, 'updateText'): self.closePersistentEditor(prevCell) prevCell.updateText() self.resizeRowToContents(prevCell.row()) except RuntimeError: pass # avoid non-repeatable error involving deleted c++ object if newCell: self.openPersistentEditor(newCell) def endEditor(self): """End persistent editors by changing active cells. """ self.setCurrentCell(-1, -1) def setFont(self, font): """Override to avoid setting fonts of inactive cells. Arguments: font -- the font to set """ global defaultFont defaultFont = font def changeInLinkSelectMode(self, active=True): """Change the internal link select mode. Changes the internal variable (controlling hover) and signals the tree. Arguments: active -- if True, starts the mode, o/w ends """ self.inLinkSelectActive = active self.inLinkSelectMode.emit(active) def updateInLinkSelectMode(self, active=True): """Update the internal link select mode. Updates the internal variable (controlling hover). Arguments: active -- if True, starts the mode, o/w ends """ self.inLinkSelectActive = active def highlightSearch(self, wordList=None, regExpList=None): """Highlight any found search terms. Arguments: wordList -- list of words to highlight regExpList -- a list of regular expression objects to highlight """ backColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.Highlight) foreColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.HighlightedText) charFormat = QTextCharFormat() charFormat.setBackground(backColor) charFormat.setForeground(foreColor) spot = self.treeView.selectionModel().selectedSpots()[0] if wordList is None: wordList = [] if regExpList is None: regExpList = [] for regExp in regExpList: for match in regExp.finditer('\n'.join(spot.nodeRef. output(spotRef=spot))): matchText = match.group().lower() if matchText not in wordList: wordList.append(matchText) cells = [] completedCells = [] for word in wordList: cells.extend(self.findItems(word, Qt.MatchFlag.MatchFixedString | Qt.MatchFlag.MatchContains)) for cell in cells: if hasattr(cell, 'doc') and cell not in completedCells: highlighter = SearchHighlighter(wordList, charFormat, cell.doc) completedCells.append(cell) def highlightMatch(self, searchText='', regExpObj=None, cellNum=0, skipMatches=0): """Highlight a specific search result. Arguments: searchText -- the text to find in a non-regexp search regExpObj -- the regular expression to find if searchText is blank cellNum -- the vertical position (field number) of the cell skipMatches -- number of previous matches to skip in this field """ backColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.Highlight) foreColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.HighlightedText) charFormat = QTextCharFormat() charFormat.setBackground(backColor) charFormat.setForeground(foreColor) cellNum += 1 # skip title line cell = self.item(cellNum, 1) highlighter = MatchHighlighter(cell.doc, charFormat, searchText, regExpObj, skipMatches) def adjustSizes(self): """Update the column widths and row heights. """ self.resizeColumnToContents(0) if self.columnWidth(0) < _minColumnWidth: self.setColumnWidth(0, _minColumnWidth) self.setColumnWidth(1, max(self.width() - self.columnWidth(0) - self.verticalScrollBar().width() - 5, _minColumnWidth)) self.resizeRowsToContents() def focusInEvent(self, event): """Handle focus-in to start an editor when tab is used. Arguments: event -- the focus in event """ if event.reason() == Qt.FocusReason.TabFocusReason: for row in range(self.rowCount()): cell = self.item(row, 1) if hasattr(cell, 'doc'): self.setCurrentItem(cell) break elif event.reason() == Qt.FocusReason.BacktabFocusReason: for row in range(self.rowCount() - 1, -1, -1): cell = self.item(row, 1) if hasattr(cell, 'doc'): self.setCurrentItem(cell) break super().focusInEvent(event) def resizeEvent(self, event): """Update view if was collaped by splitter. """ if ((event.oldSize().height() == 0 and event.size().height()) or (event.oldSize().width() == 0 and event.size().width())): self.updateContents() self.adjustSizes() return super().resizeEvent(event) def dragEnterEvent(self, event): """Accept drags of files to this window. Arguments: event -- the drag event object """ if event.mimeData().hasUrls(): event.accept() def dragMoveEvent(self, event): """Accept drags of files to this window. Arguments: event -- the drag event object """ cell = self.itemAt(event.position().toPoint()) if (isinstance(cell, DataEditCell) and getattr(dataeditors, cell.field.editorClassName).dragLinkEnabled): event.accept() else: event.ignore() def dropEvent(self, event): """Open a file dropped onto this window. Arguments: event -- the drop event object """ cell = self.itemAt(event.position().toPoint()) fileList = event.mimeData().urls() if fileList and isinstance(cell, DataEditCell): self.setCurrentItem(cell) self.setFocus() self.itemDelegate().lastEditor.addDroppedUrl(fileList[0]. toLocalFile()) def mousePressEvent(self, event): """Handle ctrl + click to follow links. Arguments: event -- the mouse event """ if (event.button() == Qt.MouseButton.LeftButton and event.modifiers() == Qt.KeyboardModifier.ControlModifier): cell = self.itemAt(event.position().toPoint()) if cell and isinstance(cell, DataEditCell): xOffest = (event.position().toPoint().x() - self.columnViewportPosition(cell.column())) yOffset = (event.position().toPoint().y() - self.rowViewportPosition(cell.row())) pt = QPointF(xOffest, yOffset) pos = cell.doc.documentLayout().hitTest(pt, Qt.HitTestAccuracy.ExactHit) if pos >= 0: cursor = QTextCursor(cell.doc) cursor.setPosition(pos) address = cursor.charFormat().anchorHref() if address: if address.startswith('#'): (self.treeView.selectionModel(). selectNodeById(address[1:])) else: # check for relative path if urltools.isRelative(address): defaultPath = (globalref.mainControl. defaultPathObj(True)) address = urltools.toAbsolute(address, str(defaultPath)) dataeditors.openExtUrl(address) event.accept() else: super().mousePressEvent(event) def mouseMoveEvent(self, event): """Handle mouse move event to create editors on hover. Arguments: event -- the mouse event """ cell = self.itemAt(event.position().toPoint()) if cell and hasattr(cell, 'doc'): oldCell = self.currentItem() if (cell != oldCell and cell != self.prevHoverCell and not self.inLinkSelectActive): # save scroll position for unlimited height editors self.itemDelegate().tallEditScrollPos = (self. verticalScrollBar(). value()) self.prevHoverCell = cell self.hoverFocusActive.emit() self.setFocus() if oldCell and hasattr(oldCell, 'doc'): # these lines result in two calls to moveEditor, but seems # to be necessary to avoid race that leaves stray editors self.moveEditor(None, oldCell) self.setCurrentItem(None) try: self.setCurrentItem(cell) except RuntimeError: # catch error if view updates due to node rename ending pass else: self.prevHoverCell = None class SearchHighlighter(QSyntaxHighlighter): """Class override to highlight search terms in cell text. Used to highlight search words from a list. """ def __init__(self, wordList, charFormat, doc): """Initialize the highlighter with the text document. Arguments: wordList -- list of search terms charFormat -- the formatting to apply doc -- the text document """ super().__init__(doc) self.wordList = wordList self.charFormat = charFormat def highlightBlock(self, text): """Override method to highlight search terms in block of text. Arguments: text -- the text to highlight """ for word in self.wordList: pos = text.lower().find(word, 0) while pos >= 0: self.setFormat(pos, len(word), self.charFormat) pos = text.lower().find(word, pos + len(word)) class MatchHighlighter(QSyntaxHighlighter): """Class override to highlight a specific search result in cell text. Used to highlight a text or reg exp match. """ def __init__(self, doc, charFormat, searchText='', regExpObj=None, skipMatches=0): """Initialize the highlighter with the text document. Arguments: doc -- the text document charFormat -- the formatting to apply searchText -- the text to find if no regexp is given regExpObj -- the regular expression to find if given skipMatches -- number of previous matches to skip """ super().__init__(doc) self.charFormat = charFormat self.searchText = searchText self.regExpObj = regExpObj self.skipMatches = skipMatches def highlightBlock(self, text): """Override method to highlight a match in block of text. Arguments: text -- the text to highlight """ pos = matchLen = 0 for matchNum in range(self.skipMatches + 1): pos += matchLen if self.regExpObj: match = self.regExpObj.search(text, pos) pos = match.start() if match else -1 matchLen = len(match.group()) if match else 0 else: pos = text.lower().find(self.searchText, pos) matchLen = len(self.searchText) if pos >= 0: self.setFormat(pos, matchLen, self.charFormat) TreeLine-3.2.1/source/exports.py000066400000000000000000002621241506556630100166200ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # exports.py, provides classes for a file export dialog and export functions # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import os.path import pathlib import re import json import copy import io import zipfile import csv import shutil from xml.etree import ElementTree from PyQt6.QtCore import Qt from PyQt6.QtGui import QFontInfo from PyQt6.QtWidgets import (QApplication, QButtonGroup, QCheckBox, QDialog, QFileDialog, QGroupBox, QHBoxLayout, QLabel, QMessageBox, QRadioButton, QSpinBox, QVBoxLayout, QWizard, QWizardPage) import treestructure import treenode import treeformats import nodeformat import fieldformat import treeoutput import treemaincontrol import imports import urltools import globalref try: from __main__ import __version__ except ImportError: __version__ = '' try: from __main__ import templatePath except ImportError: templatePath = None _bookmarkTitle = _('Bookmarks') _odfNamespace = {'fo': 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0', 'office': 'urn:oasis:names:tc:opendocument:xmlns:office:1.0', 'style': 'urn:oasis:names:tc:opendocument:xmlns:style:1.0', 'svg': 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0', 'text': 'urn:oasis:names:tc:opendocument:xmlns:text:1.0', 'manifest': 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'} _intLinkRe = re.compile(r']*href="#(.*?)"[^>]*>.*?', re.I | re.S) _genLinkRe = re.compile(r']*href="(.*?)"[^>]*>.*?', re.I | re.S) _imgLinkRe = re.compile(r']*src="(.*?)"[^>]*>.*?', re.I | re.S) _idReplaceCharsRe = re.compile(r'[^a-zA-Z0-9_-]+') class ExportControl: """Control to do file exports for tree branches and nodes. """ def __init__(self, structure, selectionModel, defaultPathObj, printData): """Initialize export control object. Arguments: structure -- the tree structure ref for exporting the entire tree selectionModel -- the selection model for partial exports defaultPathObj -- path object to use as file dialog default printData -- a ref to print data for old treeline exports """ self.structure = structure self.selectedSpots = selectionModel.selectedSpots() self.selectedNodes = selectionModel.selectedNodes() self.defaultPathObj = defaultPathObj self.printData = printData def interactiveExport(self): """Prompt the user for types, options, filename & proceed with export. Return True if export is successful. """ exportMethods = {'htmlSingle': self.exportHtmlSingle, 'htmlNavSingle': self.exportHtmlNavSingle, 'htmlPages': self.exportHtmlPages, 'htmlTables': self.exportHtmlTables, 'htmlLiveLink': self.exportHtmlLiveLink, 'htmlLiveSingle': self.exportHtmlLiveSingle, 'textTitles': self.exportTextTitles, 'textPlain': self.exportTextPlain, 'textTableMultiCsv': self.exportTextTableMultiCsv, 'textTableCsv': self.exportTextTableCsv, 'textTableTab': self.exportTextTableTab, 'oldTreeLine': self.exportOldTreeLine, 'treeLineSubtree': self.exportSubtree, 'xmlGeneric': self.exportXmlGeneric, 'odfText': self.exportOdfText, 'bookmarksHtml': self.exportBookmarksHtml, 'bookmarksXbel': self.exportBookmarksXbel} exportDialog = ExportDialog(len(self.selectedNodes), QApplication.activeWindow()) if exportDialog.exec() == QDialog.DialogCode.Accepted: result = exportMethods[ExportDialog.currentSubtype]() QApplication.restoreOverrideCursor() return result return False def getFileName(self, dialogTitle, defaultExt='txt'): """Prompt the user for a filename and return a path object. Arguments: dialogTitle -- the title for use on the dialog window defaultExt -- the default file extension from globalref """ filters = ';;'.join((globalref.fileFilters[defaultExt], globalref.fileFilters['all'])) defaultExt = defaultExt[:4] if self.defaultPathObj.is_file(): self.defaultPathObj = self.defaultPathObj.with_suffix('.' + defaultExt) filePath, selectFilter = QFileDialog.getSaveFileName(QApplication. activeWindow(), dialogTitle, str(self.defaultPathObj), filters) if filePath: pathObj = pathlib.Path(filePath) if not pathObj.suffix: pathObj = pathObj.with_suffix('.' + defaultExt) return pathObj return None def exportHtmlSingle(self, pathObj=None): """Export to a single web page, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export HTML'), 'html') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedSpots = self.structure.rootSpots() outputGroup = treeoutput.OutputGroup(self.selectedSpots, ExportDialog.includeRoot, ExportDialog.exportWhat != ExportDialog.selectNode, ExportDialog.openOnly) outputGroup.addAnchors() if outputGroup.hasPrefixes(): outputGroup.combineAllSiblings() outputGroup.addBlanksBetween() outputGroup.addIndents() outGroups = outputGroup.splitColumns(ExportDialog.numColumns) htmlTitle = pathObj.stem indent = globalref.genOptions['IndentOffset'] lines = ['', '', '', '', '{0}'.format(htmlTitle), '', '', ''] if ExportDialog.addHeader: headerText = (globalref.mainControl.activeControl.printData. formatHeaderFooter(True)) if headerText: lines.append(headerText) lines.extend(['', '', '
    ']) lines.extend(outGroups[0].getLines()) for group in outGroups[1:]: lines.append('') lines.extend(group.getLines()) lines.extend(['
    ']) if ExportDialog.addHeader: footerText = (globalref.mainControl.activeControl.printData. formatHeaderFooter(False)) if footerText: lines.append(footerText) lines.extend(['', '']) with pathObj.open('w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) return True def exportHtmlNavSingle(self, pathObj=None): """Export single web page with a navigation pane, ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export HTML'), 'html') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedSpots = self.structure.rootSpots() outputGroup = treeoutput.OutputGroup(self.selectedSpots, ExportDialog.includeRoot, True, ExportDialog.openOnly) outputGroup.addAnchors(ExportDialog.navPaneLevels) if outputGroup.hasPrefixes(): outputGroup.combineAllSiblings() outputGroup.addBlanksBetween() outputGroup.addIndents() htmlTitle = pathObj.stem indent = globalref.genOptions['IndentOffset'] lines = ['', '', '', '', '{0}'.format(htmlTitle), '', '', '', '') level -= 1 lines.extend(['', '
    ']) if ExportDialog.addHeader: headerText = (globalref.mainControl.activeControl.printData. formatHeaderFooter(True)) if headerText: lines.append(headerText) lines.extend(outputGroup.getLines()) if ExportDialog.addHeader: footerText = (globalref.mainControl.activeControl.printData. formatHeaderFooter(False)) if footerText: lines.append(footerText) lines.extend(['
    ', '', '']) with pathObj.open('w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) return True def exportHtmlPages(self, pathObj=None): """Export multiple web pages with navigation, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: path = QFileDialog.getExistingDirectory(QApplication. activeWindow(), _('TreeLine - Export HTML'), str(self.defaultPathObj)) if not path: return False pathObj = pathlib.Path(path) QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) oldDir = os.getcwd() os.chdir(str(pathObj)) indent = globalref.genOptions['IndentOffset'] cssLines = ['#sidebar {', ' width: 16em;', ' float: left;', ' border-right: 1px solid black;', '}', '#sidebar div {{margin-left: {0}em;}}'.format(indent), '#content {', ' margin-left: 16em;', ' border-left: 1px solid black;', ' padding-left: 6px;', '}'] with open('default.css', 'w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in cssLines]) if ExportDialog.exportWhat != ExportDialog.entireTree: self.structure = treestructure.TreeStructure(topNodes=self. selectedNodes, addSpots=False) if len(self.structure.childList) > 1: self.structure = treestructure.TreeStructure(topNodes=self. structure.childList, addSpots=False) rootType = nodeformat.NodeFormat(treeformats.defaultTypeName, self.structure.treeFormats, addDefaultField=True) self.structure.treeFormats.addTypeIfMissing(rootType) root = treenode.TreeNode(self.structure. treeFormats[treeformats.defaultTypeName]) root.setTitle(treestructure.defaultRootTitle) self.structure.addNodeDictRef(root) root.childList = self.structure.childList self.structure.childList = [root] pathDict = {} _setHtmlDirectories(self.structure.childList[0], pathDict, pathObj, set()) _writeHtmlPage(self.structure.childList[0], None, None, pathDict) os.chdir(oldDir) return True def exportHtmlTables(self, pathObj=None): """Export to multiple web page tables, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: path = QFileDialog.getExistingDirectory(QApplication. activeWindow(), _('TreeLine - Export HTML'), str(self.defaultPathObj)) if not path: return False pathObj = pathlib.Path(path) QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) oldDir = os.getcwd() os.chdir(str(pathObj)) if ExportDialog.exportWhat != ExportDialog.entireTree: self.structure = treestructure.TreeStructure(topNodes=self. selectedNodes, addSpots=False) if len(self.structure.childList) > 1: self.structure = treestructure.TreeStructure(topNodes=self. structure.childList, addSpots=False) rootType = nodeformat.NodeFormat(treeformats.defaultTypeName, self.structure.treeFormats, addDefaultField=True) self.structure.treeFormats.addTypeIfMissing(rootType) root = treenode.TreeNode(self.structure. treeFormats[treeformats.defaultTypeName]) name = self.defaultPathObj.stem if not name: name = treestructure.defaultRootTitle root.setTitle(name) self.structure.addNodeDictRef(root) root.childList = self.structure.childList self.structure.childList = [root] pathDict = {} _setHtmlDirectories(self.structure.childList[0], pathDict, pathObj, set(), False) _writeHtmlTable(self.structure.childList[0], None, pathDict) os.chdir(oldDir) return True def exportHtmlLiveLink(self, pathObj=None): """Export a live tree view, linked back to the source file. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: path = QFileDialog.getExistingDirectory(QApplication. activeWindow(), _('TreeLine - Export HTML'), str(self.defaultPathObj)) if not path: return False pathObj = pathlib.Path(path) QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) control = globalref.mainControl prefPath = templatePath + '/exports' if templatePath else '' htmlPath = control.findResourceFile('live_tree_export.html', 'templates/exports', prefPath) jsPath = control.findResourceFile('live_tree_export.js', 'templates/exports', prefPath) cssPath = control.findResourceFile('live_tree_export.css', 'templates/exports', prefPath) if not htmlPath or not jsPath or not cssPath: QApplication.restoreOverrideCursor() QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - export template files not found.\n' 'Check your TreeLine installation.')) return False refPath = globalref.mainControl.activeControl.filePathObj if not refPath: QApplication.restoreOverrideCursor() QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - cannot link to unsaved TreeLine ' 'file.\nSave the file and retry.')) return False try: refPath = pathlib.Path(os.path.relpath(str(refPath), str(pathObj))) except ValueError: QApplication.restoreOverrideCursor() msg = _('Warning - no relative path from "{0}" to "{1}".\n' 'Continue with absolute path?').format(pathObj.as_posix(), refPath.as_posix()) ans = QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', msg, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.Yes) if ans == QMessageBox.StandardButton.No: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) fileStem = refPath.stem outPath = pathObj / (fileStem + '.html') with htmlPath.open(encoding='utf-8') as fileIn: with outPath.open('w', encoding='utf-8') as fileOut: for line in fileIn: if '' in line: line = re.sub(r'<title>.*', '{0}'.format(fileStem), line) elif 'dataFilePath' in line: line = line.replace('""', '"{0}"'. format(refPath.parent.as_posix())) elif 'dataFileName' in line: line = line.replace('""', '"{0}"'.format(refPath.name)) fileOut.write(line) shutil.copy(str(jsPath), str(pathObj)) shutil.copy(str(cssPath), str(pathObj)) return True def exportHtmlLiveSingle(self, pathObj=None): """Export a live tree view to a single file (embedded data). Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export HTML'), 'html') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) control = globalref.mainControl prefPath = templatePath + '/exports' if templatePath else '' htmlPath = control.findResourceFile('live_tree_export.html', 'templates/exports', prefPath) jsPath = control.findResourceFile('live_tree_export.js', 'templates/exports', prefPath) cssPath = control.findResourceFile('live_tree_export.css', 'templates/exports', prefPath) if not htmlPath or not jsPath or not cssPath: QApplication.restoreOverrideCursor() QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - export template files not found.\n' 'Check your TreeLine installation.')) return False if ExportDialog.exportWhat == ExportDialog.entireTree: fileData = self.structure.fileData() else: self.structure = treestructure.TreeStructure(topNodes=self. selectedNodes, addSpots=False) fileData = self.structure.fileData() if ExportDialog.exportWhat == ExportDialog.selectNode: topNodeIds = set([node.uId for node in self.structure.childList]) nodeData = [data for data in fileData['nodes'] if data['uid'] in topNodeIds] for data in nodeData: data['children'] = [] fileData['nodes'] = nodeData with htmlPath.open(encoding='utf-8') as htmlIn: with pathObj.open('w', encoding='utf-8') as htmlOut: for line in htmlIn: if 'stylesheet' in line: htmlOut.write('') elif '' in line: line = re.sub(r'<title>.*', '{0}'. format(pathObj.stem), line) htmlOut.write(line) elif 'application/json' in line: htmlOut.write(line) json.dump(fileData, htmlOut, indent=2, sort_keys=True) elif 'dataFileName' in line: htmlOut.write(line) with jsPath.open(encoding='utf-8') as jsIn: htmlOut.write(jsIn.read()) elif 'script src=' not in line: htmlOut.write(line) return True def exportTextTitles(self, pathObj=None): """Export tabbed title text, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export Text Titles'), 'txt') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedSpots = self.structure.rootSpots() if ExportDialog.exportWhat == ExportDialog.selectNode: lines = [spot.nodeRef.title(spot) for spot in self.selectedSpots] else: treeView = (globalref.mainControl.activeControl.activeWindow. treeView) lines = [] for rootSpot in self.selectedSpots: for spot, level in rootSpot.levelSpotDescendantGen(treeView, ExportDialog.includeRoot, None, ExportDialog.openOnly): lines.append('\t' * level + spot.nodeRef.title(spot)) try: with pathObj.open('w', encoding=globalref.localTextEncoding) as f: f.writelines([(line + '\n') for line in lines]) except UnicodeEncodeError: with pathObj.open('w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) return True def exportTextPlain(self, pathObj=None): """Export unformatted text for all output, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export Plain Text'), 'txt') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedSpots = self.structure.rootSpots() lines = [] if ExportDialog.exportWhat == ExportDialog.selectNode: for rootSpot in self.selectedSpots: lines.extend(rootSpot.nodeRef.output(True, False, rootSpot)) if rootSpot.nodeRef.formatRef.spaceBetween: lines.append('') else: treeView = (globalref.mainControl.activeControl.activeWindow. treeView) for rootSpot in self.selectedSpots: for spot, level in rootSpot.levelSpotDescendantGen(treeView, ExportDialog.includeRoot, None, ExportDialog.openOnly): lines.extend(spot.nodeRef.output(True, False, spot)) if spot.nodeRef.formatRef.spaceBetween: lines.append('') try: with pathObj.open('w', encoding=globalref.localTextEncoding) as f: f.writelines([(line + '\n') for line in lines]) except UnicodeEncodeError: with pathObj.open('w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) return True def exportTextTableMultiCsv(self, pathObj=None): """Export descendant CSV delimited text table with level numbers. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export Text Tables'), 'csv') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedSpots = self.structure.rootSpots() treeView = (globalref.mainControl.activeControl.activeWindow.treeView) types = set() headings = [] for rootSpot in self.selectedSpots: for spot, level in rootSpot.levelSpotDescendantGen(treeView, ExportDialog.includeRoot, None, ExportDialog.openOnly): nodeFormat = spot.nodeRef.formatRef if nodeFormat not in types: for fieldName in nodeFormat.fieldNames(): if fieldName not in headings: headings.append(fieldName) types.add(nodeFormat) lines = [['Level'] + headings] for rootSpot in self.selectedSpots: for spot, level in rootSpot.levelSpotDescendantGen(treeView, ExportDialog.includeRoot, None, ExportDialog.openOnly): newLine = [spot.nodeRef.data.get(head, '') for head in headings] lines.append([repr(level)] + newLine) try: with pathObj.open('w', newline='', encoding=globalref.localTextEncoding) as f: writer = csv.writer(f) writer.writerows(lines) except UnicodeEncodeError: with pathObj.open('w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerows(lines) return True def exportTextTableCsv(self, pathObj=None): """Export child CSV delimited text table, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export Text Tables'), 'csv') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.selectNode: nodeList = self.selectedNodes else: nodeList = [] for node in self.selectedNodes: nodeList.extend(node.childList) types = set() headings = [] for node in nodeList: nodeFormat = node.formatRef if nodeFormat not in types: for fieldName in nodeFormat.fieldNames(): if fieldName not in headings: headings.append(fieldName) types.add(nodeFormat) lines = [headings] for node in nodeList: lines.append([node.data.get(head, '') for head in headings]) try: with pathObj.open('w', newline='', encoding=globalref.localTextEncoding) as f: writer = csv.writer(f) writer.writerows(lines) except UnicodeEncodeError: with pathObj.open('w', newline='', encoding='utf-8') as f: writer = csv.writer(f) writer.writerows(lines) return True def exportTextTableTab(self, pathObj=None): """Export child tab delimited text table, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export Text Tables'), 'txt') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.selectNode: nodeList = self.selectedNodes else: nodeList = [] for node in self.selectedNodes: nodeList.extend(node.childList) types = set() headings = [] for node in nodeList: nodeFormat = node.formatRef if nodeFormat not in types: for fieldName in nodeFormat.fieldNames(): if fieldName not in headings: headings.append(fieldName) types.add(nodeFormat) lines = ['\t'.join(headings)] for node in nodeList: lines.append('\t'.join([node.data.get(head, '') for head in headings])) try: with pathObj.open('w', encoding=globalref.localTextEncoding) as f: f.writelines([(line + '\n') for line in lines]) except UnicodeEncodeError: with pathObj.open('w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) return True def exportOldTreeLine(self, pathObj=None): """Export old TreeLine version (2.0.x), use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export TreeLine Subtree'), 'trl') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat != ExportDialog.entireTree: self.structure = treestructure.TreeStructure(topNodes=self. selectedNodes, addSpots=False) addDescend = ExportDialog.exportWhat != ExportDialog.selectNode addChildren = addDescend if len(self.structure.childList) > 1: if not addDescend: addChildren = True self.structure = treestructure.TreeStructure(topNodes=self. structure.childList, addSpots=False) rootType = nodeformat.NodeFormat(treeformats.defaultTypeName, self.structure.treeFormats, addDefaultField=True) self.structure.treeFormats.addTypeIfMissing(rootType) root = treenode.TreeNode(self.structure. treeFormats[treeformats.defaultTypeName]) root.setTitle(treestructure.defaultRootTitle) self.structure.addNodeDictRef(root) root.childList = self.structure.childList self.structure.childList = [root] idDict = {} for node in self.structure.childList[0].descendantGen(): _setOldUniqueId(idDict, node) idDict = {i[1]: i[0] for i in idDict.items()} # reverse (new id keys) rootElement = _oldElementXml(self.structure.childList[0], self.structure, idDict, addChildren=addChildren, addDescend=addDescend) if __version__: rootElement.set('tlversion', __version__) rootElement.attrib.update(_convertOldPrintData(self.printData. fileData())) elementTree = ElementTree.ElementTree(rootElement) elementTree.write(str(pathObj), 'utf-8', True) return True def exportSubtree(self, pathObj=None): """Export TreeLine subtree, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export TreeLine Subtree'), 'trlnsave') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) self.structure = treestructure.TreeStructure(topNodes=self. selectedNodes, addSpots=False) fileData = self.structure.fileData() fileData['properties'].update(self.printData.fileData()) if ExportDialog.exportWhat == ExportDialog.selectNode: topNodeIds = set([node.uId for node in self.structure.childList]) nodeData = [data for data in fileData['nodes'] if data['uid'] in topNodeIds] for data in nodeData: data['children'] = [] fileData['nodes'] = nodeData indent = 3 if globalref.genOptions['PrettyPrint'] else 0 with pathObj.open('w', encoding='utf-8', newline='\n') as f: json.dump(fileData, f, indent=indent, sort_keys=True) return True def exportXmlGeneric(self, pathObj=None): """Export generic XML, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export Generic XML'), 'xml') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedNodes = self.structure.childList addBranches = ExportDialog.exportWhat != ExportDialog.selectNode if len(self.selectedNodes) > 1: rootElement = ElementTree.Element(treeformats.defaultTypeName) for node in self.selectedNodes: rootElement.append(_createGenericXml(node, addBranches)) else: rootElement = _createGenericXml(self.selectedNodes[0], addBranches) elementTree = ElementTree.ElementTree(rootElement) elementTree.write(str(pathObj), 'utf-8', True) return True def exportOdfText(self, pathObj=None): """Export an ODF text file, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export ODF Text'), 'odt') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedSpots = self.structure.rootSpots() addBranches = ExportDialog.exportWhat != ExportDialog.selectNode for prefix, uri in _odfNamespace.items(): ElementTree.register_namespace(prefix, uri) versionAttr = {'office:version': '1.0'} fontInfo = QFontInfo(globalref.mainControl.activeControl. activeWindow.editorSplitter.widget(0). font()) fontAttr = {'style:font-pitch': 'fixed' if fontInfo.fixedPitch() else 'variable', 'style:name': fontInfo.family(), 'svg:font-family': fontInfo.family()} fontElem = _addOdfElement('office:font-face-decls') _addOdfElement('style:font-face', fontElem, fontAttr) fontSizeDelta = 2 contentRoot = _addOdfElement('office:document-content', attr=versionAttr) contentRoot.append(fontElem) contentBodyElem = _addOdfElement('office:body', contentRoot) contentTextElem = _addOdfElement('office:text', contentBodyElem) maxLevel = 0 for spot in self.selectedSpots: level = _addOdfText(spot, contentTextElem, addBranches) maxLevel = max(level, maxLevel) manifestRoot = _addOdfElement('manifest:manifest') _addOdfElement('manifest:file-entry', manifestRoot, {'manifest:media-type': 'application/vnd.oasis.opendocument.text', 'manifest:full-path': '/'}) _addOdfElement('manifest:file-entry', manifestRoot, {'manifest:media-type': 'text/xml', 'manifest:full-path': 'content.xml'}) _addOdfElement('manifest:file-entry', manifestRoot, {'manifest:media-type': 'text/xml', 'manifest:full-path': 'styles.xml'}) styleRoot = _addOdfElement('office:document-styles', attr=versionAttr) styleRoot.append(fontElem) stylesElem = _addOdfElement('office:styles', styleRoot) defaultStyleElem = _addOdfElement('style:default-style', stylesElem, {'style:family': 'paragraph'}) _addOdfElement('style:paragraph-properties', defaultStyleElem, {'style:writing-mode': 'page'}) _addOdfElement('style:text-properties', defaultStyleElem, {'fo:font-size': '{0}pt'.format(fontInfo.pointSize()), 'fo:hyphenate': 'false', 'style:font-name': fontInfo.family()}) _addOdfElement('style:style', stylesElem, {'style:name': 'Standard', 'style:class': 'text', 'style:family': 'paragraph'}) bodyStyleElem = _addOdfElement('style:style', stylesElem, {'style:name': 'Text_20_body', 'style:display-name': 'Text body', 'style:class': 'text', 'style:family': 'paragraph', 'style:parent-style-name': 'Standard'}) _addOdfElement('style:paragraph-properties', bodyStyleElem, {'fo:margin-bottom': '6.0pt'}) headStyleElem = _addOdfElement('style:style', stylesElem, {'style:name': 'Heading', 'style:class': 'text', 'style:family': 'paragraph', 'style:next-style-name': 'Text_20_body', 'style:parent-style-name': 'Standard'}) _addOdfElement('style:paragraph-properties', headStyleElem, {'fo:keep-with-next': 'always', 'fo:margin-bottom': '6.0pt', 'fo:margin-top': '12.0pt'}) _addOdfElement('style:text-properties', headStyleElem, {'fo:font-size': '{0}pt'.format(fontInfo.pointSize() + fontSizeDelta), 'style:font-name': fontInfo.family()}) outlineStyleElem = _addOdfElement('text:outline-style') for level in range(1, maxLevel + 1): size = fontInfo.pointSize() if level <= 2: size += 2 * fontSizeDelta elif level <= 4: size += fontSizeDelta levelStyleElem = _addOdfElement('style:style', stylesElem, {'style:name': 'Heading_20_{0}'.format(level), 'style:display-name': 'Heading {0}'.format(level), 'style:class': 'text', 'style:family': 'paragraph', 'style:parent-style-name': 'Heading', 'style:default-outline-level': '{0}'.format(level)}) levelTextElem = _addOdfElement('style:text-properties', levelStyleElem, {'fo:font-size': '{0}pt'.format(size), 'fo:font-weight': 'bold'}) if level % 2 == 0: levelTextElem.set('fo:font-style', 'italic') _addOdfElement('text:outline-level-style', outlineStyleElem, {'text:level': '{0}'.format(level), 'style:num-format': ''}) stylesElem.append(outlineStyleElem) autoStyleElem = _addOdfElement('office:automatic-styles', styleRoot) pageLayElem = _addOdfElement('style:page-layout', autoStyleElem, {'style:name': 'pm1'}) _addOdfElement('style:page-layout-properties', pageLayElem, {'fo:margin-bottom': '0.75in', 'fo:margin-left': '0.75in', 'fo:margin-right': '0.75in', 'fo:margin-top': '0.75in', 'fo:page-height': '11in', 'fo:page-width': '8.5in', 'style:print-orientation': 'portrait'}) masterStyleElem = _addOdfElement('office:master-styles', styleRoot) _addOdfElement('style:master-page', masterStyleElem, {'style:name': 'Standard', 'style:page-layout-name': 'pm1'}) with zipfile.ZipFile(str(pathObj), 'w', zipfile.ZIP_DEFLATED) as odfZip: _addElemToZip(odfZip, contentRoot, 'content.xml') _addElemToZip(odfZip, manifestRoot, 'META-INF/manifest.xml') _addElemToZip(odfZip, styleRoot, 'styles.xml') return True def exportBookmarksHtml(self, pathObj=None): """Export HTML format bookmarks, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export HTML Bookmarks'), 'html') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedNodes = self.structure.childList addBranches = ExportDialog.exportWhat != ExportDialog.selectNode title = _bookmarkTitle if len(self.selectedNodes) == 1 and addBranches: title = self.selectedNodes[0].title() self.selectedNodes = self.selectedNodes[0].childList lines = ['', '', '{0}'.format(title), '

    {0}

    '.format(title)] for node in self.selectedNodes: lines.extend(_exportHtmlBookmarks(node, addBranches)) with pathObj.open('w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) return True def exportBookmarksXbel(self, pathObj=None): """Export XBEL format bookmarks, use ExportDialog options. Prompt user for path if not given in argument. Return True on successful export. Arguments: pathObj -- use if given, otherwise prompt user """ if not pathObj: pathObj = self.getFileName(_('TreeLine - Export XBEL Bookmarks'), 'xml') if not pathObj: return False QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if ExportDialog.exportWhat == ExportDialog.entireTree: self.selectedNodes = self.structure.childList addBranches = ExportDialog.exportWhat != ExportDialog.selectNode title = _bookmarkTitle if len(self.selectedNodes) == 1 and addBranches: title = self.selectedNodes[0].title() self.selectedNodes = self.selectedNodes[0].childList rootElem = ElementTree.Element('xbel') titleElem = ElementTree.Element('title') titleElem.text = title rootElem.append(titleElem) for node in self.selectedNodes: rootElem.append(_exportXbel(node, addBranches)) elementTree = ElementTree.ElementTree(rootElem) with pathObj.open('wb') as f: f.write(b'\n') elementTree.write(f, 'utf-8', False) return True def _setHtmlDirectories(node, pathDict, parentPath, siblingNames, addSuffix=True): """Recursively create path obj for node and add to the path dict by uId. Arguments: node -- the node to create a path object for pathDict -- the dict of paths by uId for adding an entry parentPath -- the path of the parent node siblingNames -- set of already used sibling names addSuffix -- add '.html' suffix to file names if True """ name = node.title() maxLength = 32 if len(name) > maxLength: pos = name.rfind(' ', maxLength // 2, maxLength + 1) if pos < 0: pos = maxLength name = name[:pos] name = name.replace(' ', '_') name = _idReplaceCharsRe.sub('', name) if not name: name = 'id' elif not 'a' <= name.lower() <= 'z': name = 'id_' + name origName = name i = 1 while name in siblingNames: name = origName + '_' + repr(i) i += 1 siblingNames.add(name) pathObj = parentPath / name filePathObj = pathObj.with_suffix('.html') if addSuffix else pathObj pathDict[node.uId] = filePathObj siblings = set() for child in node.childList: _setHtmlDirectories(child, pathDict, pathObj, siblings, addSuffix) def _writeHtmlPage(node, parent, grandparent, pathDict, level=0): """Write web pages with navigation for this node and descendents. Arguments: node -- the node to write the page for parent -- the parent node (or None) grandparent -- the grandparent node (or None) pathDict -- the dict of paths by uId level -- indicates the depth and how far up the css file is """ lines = ['', '', '', '', ''.format('../' * level), '{0}'.format(node.title()), '', '', '', '
    ']) outputLines = [line + '
    ' for line in node.output()] if node.formatRef.siblingPrefix: outputLines[0] = node.formatRef.siblingPrefix + outputLines[0] if node.formatRef.siblingSuffix: outputLines[-1] += node.formatRef.siblingSuffix for i in range(len(outputLines)): startPos = 0 while True: match = _genLinkRe.search(outputLines[i], startPos) if not match: break addr = match.group(1) if addr.startswith('#'): pathObj = pathDict.get(addr[1:], None) if pathObj: relPath = os.path.relpath(str(pathObj), nodeDir) outputLines[i] = (outputLines[i][:match.start(1)] + relPath + outputLines[i][match.end(1):]) elif urltools.isRelative(addr): outputLines[i] = (outputLines[i][:match.start(1)] + '../' * level + addr + outputLines[i][match.end(1):]) startPos = match.start(1) startPos = 0 while True: match = _imgLinkRe.search(outputLines[i], startPos) if not match: break addr = match.group(1) if not addr.startswith('#') and urltools.isRelative(addr): outputLines[i] = (outputLines[i][:match.start(1)] + '../' * level + addr + outputLines[i][match.end(1):]) startPos = match.start(1) lines.extend(outputLines) lines.extend(['
    ', '', '']) with pathDict[node.uId].open('w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) if node.childList: dirObj = pathDict[node.uId].with_suffix('') if not dirObj.is_dir(): dirObj.mkdir(0o755) os.chdir(str(dirObj)) for child in node.childList: _writeHtmlPage(child, node, parent, pathDict, level + 1) os.chdir('..') def _writeHtmlTable(node, parent, pathDict, level=1): """Write web pages with tables for child data to nested directories. Arguments: node -- the node to write the page for parent -- the parent node (or None) pathDict -- the dict of paths by uId level -- the depth and how far up local links should point """ if not node.childList: return dirObj = pathDict[node.uId] if not dirObj.is_dir(): dirObj.mkdir(0o755) os.chdir(str(dirObj)) title = node.title() lines = ['', '', '', '', '{0}'.format(title), '', ''] if ExportDialog.addHeader: headerText = (globalref.mainControl.activeControl.printData. formatHeaderFooter(True)) if headerText: lines.append(headerText) lines.append('

    {0}

    '.format(title)) if parent: lines.append('

    {0}: {1}' '

    '.format(_('Parent'), parent.title())) lines.extend(['', '']) lines.extend([''.format(name) for name in node.childList[0].formatRef.fieldNames()]) lines.append('') for child in node.childList: cellList = [field.outputText(child, False, False, True) for field in child.formatRef.fields()] for i in range(len(cellList)): startPos = 0 while True: match = _genLinkRe.search(cellList[i], startPos) if not match: break addr = match.group(1) if addr.startswith('#'): pathObj = pathDict.get(addr[1:], None) if pathObj: name = pathObj.stem pathObj = pathObj / '..' / 'index.html' relPath = os.path.relpath(str(pathObj), str(dirObj)) relPath += '#' + name cellList[i] = (cellList[i][:match.start(1)] + relPath + cellList[i][match.end(1):]) elif urltools.isRelative(addr): cellList[i] = (cellList[i][:match.start(1)] + '../' * level + addr + cellList[i][match.end(1):]) startPos = match.start(1) startPos = 0 while True: match = _imgLinkRe.search(cellList[i], startPos) if not match: break addr = match.group(1) if not addr.startswith('#') and urltools.isRelative(addr): cellList[i] = (cellList[i][:match.start(1)] + '../' * level + addr + cellList[i][match.end(1):]) startPos = match.start(1) if child.childList: cellList[0] = ('{1}'. format(pathDict[child.uId].stem, cellList[0])) cellList[0] = '{1}'.format(pathDict[child.uId].stem, cellList[0]) lines.extend([''.format(cell) for cell in cellList]) lines.append('') lines.extend(['', '
    {0}
    {0}
    ']) if ExportDialog.addHeader: footerText = (globalref.mainControl.activeControl.printData. formatHeaderFooter(False)) if footerText: lines.append(footerText) lines.extend(['', '']) with open('index.html', 'w', encoding='utf-8') as f: f.writelines([(line + '\n') for line in lines]) for child in node.childList: _writeHtmlTable(child, node, pathDict, level + 1) os.chdir('..') def _oldElementXml(node, structRef, idDict, skipTypeFormats=None, extraFormats=True, addChildren=True, addDescend=True): """Return an Element object with the XML for this node's branch. Arguments: node -- the root node to save structRef -- a ref to the tree structure idDict -- a dict of new IDs to old IDs skipTypeFormats -- a set of node format types not included in XML extraFormats -- if True, includes unused format info addChildren -- if True, include data for the first level of children addDescend -- if True, add lower descendant nodes """ if skipTypeFormats == None: skipTypeFormats = set() nodeFormat = node.formatRef addFormat = nodeFormat.name not in skipTypeFormats element = ElementTree.Element(nodeFormat.name, {'item':'y'}) # add line feeds to make output somewhat readable element.tail = '\n' element.text = '\n' element.set('uniqueid', idDict[node.uId]) if addFormat: element.attrib.update(_convertOldNodeFormat(nodeFormat.storeFormat())) skipTypeFormats.add(nodeFormat.name) firstField = True for field in nodeFormat.fields(): text = node.data.get(field.name, '') if text or addFormat: fieldElement = ElementTree.SubElement(element, field.name) fieldElement.tail = '\n' if field.typeName in ('Date', 'DateTime'): text = text.replace('-', '/') if (field.typeName in ('Time', 'DateTime') and text.endswith('.000000')): text = text[:-7] linkCount = 0 startPos = 0 while True: match = _intLinkRe.search(text, startPos) if not match: break uId = idDict.get(match.group(1), '') if uId: text = text[:match.start(1)] + uId + text[match.end(1):] linkCount += 1 startPos = match.start(1) if linkCount: fieldElement.attrib['linkcount'] = repr(linkCount) fieldElement.text = text if addFormat: fieldElement.attrib.update(_convertOldFieldFormat(field. formatData())) if firstField: fieldElement.attrib['idref'] = 'y' firstField = False if addChildren: for child in node.childList: element.append(_oldElementXml(child, structRef, idDict, skipTypeFormats, False, addChildren=addDescend)) nodeFormats = [] if extraFormats: # write format info for unused formats nodeFormats = list(structRef.treeFormats.values()) if structRef.treeFormats.fileInfoFormat.fieldFormatModified: nodeFormats.append(structRef.treeFormats.fileInfoFormat) for nodeFormat in nodeFormats: if nodeFormat.name not in skipTypeFormats: formatElement = ElementTree.SubElement(element, nodeFormat.name, {'item':'n'}) formatElement.tail = '\n' formatElement.attrib.update(_convertOldNodeFormat(nodeFormat. storeFormat())) firstField = True for field in nodeFormat.fields(): fieldElement = ElementTree.SubElement(formatElement, field.name) fieldElement.tail = '\n' fieldElement.attrib.update(_convertOldFieldFormat(field. formatData())) if firstField: fieldElement.attrib['idref'] = 'y' firstField = False return element def _setOldUniqueId(idDict, node): """Set an old TreeLine unique ID for this node amd add to dict. Arguments: idDict -- a dict of old IDs to new IDs. node -- the node to give an old ID """ nodeFormat = node.formatRef idField = next(iter(nodeFormat.fieldDict.values())) uId = idField.outputText(node, True, True, nodeFormat.formatHtml) uId = uId.strip().split('\n', 1)[0] maxLength = 50 if len(uId) > maxLength: pos = uId.rfind(' ', maxLength // 2, maxLength + 1) if pos < 0: pos = maxLength uId = uId[:pos] uId = uId.replace(' ', '_').lower() uId = _idReplaceCharsRe.sub('', uId) if not uId: uId = 'id_1' elif not 'a' <= uId <= 'z': uId = 'id_' + uId if uId in idDict: if uId == 'id_1': uId = 'id' i = 1 while uId + '_' + repr(i) in idDict: i += 1 uId = uId + '_' + repr(i) idDict[uId] = node.uId def _convertOldNodeFormat(attrib): """Return old XML node format attributes from current data. Arguments: attrib -- current node format data attributes """ if 'spacebetween' in attrib and not attrib['spacebetween']: attrib['spacebetween'] = 'n' for key in ('formathtml', 'bullets', 'tables'): if key in attrib and attrib[key]: attrib[key] = 'y' attrib['line0'] = attrib.get('titleline', '') del attrib['titleline'] for i, line in enumerate(attrib['outputlines'], 1): attrib['line' + repr(i)] = line del attrib['outputlines'] del attrib['formatname'] del attrib['fields'] return attrib def _convertOldFieldFormat(attrib): """Return old XML field format attributes from current data. Arguments: attrib -- current field format data attributes """ if 'fieldtype' in attrib: attrib['type'] = attrib['fieldtype'] del attrib['fieldtype'] for key in ('lines', 'sortkeynum'): if key in attrib: attrib[key] = repr(attrib[key]) if 'sortkeyfwd' in attrib and not attrib['sortkeyfwd']: attrib['sortkeydir'] = 'r' if 'evalhtml' in attrib: attrib['evalhtml'] = 'y' if attrib['evalhtml'] else 'n' if attrib['type'] in ('Date', 'Time', 'DateTime'): fieldFormat = attrib.get('format', '') if fieldFormat: fieldFormat = fieldFormat.replace('%A', 'dddd') fieldFormat = fieldFormat.replace('%a', 'ddd') fieldFormat = fieldFormat.replace('%d', 'dd') fieldFormat = fieldFormat.replace('%-d', 'd') fieldFormat = fieldFormat.replace('%B', 'MMMM') fieldFormat = fieldFormat.replace('%b', 'MMM') fieldFormat = fieldFormat.replace('%m', 'MM') fieldFormat = fieldFormat.replace('%-m', 'M') fieldFormat = fieldFormat.replace('%Y', 'yyyy') fieldFormat = fieldFormat.replace('%y', 'yy') fieldFormat = fieldFormat.replace('%H', 'HH') fieldFormat = fieldFormat.replace('%-H', 'H') fieldFormat = fieldFormat.replace('%I', 'hh') fieldFormat = fieldFormat.replace('%-I', 'h') fieldFormat = fieldFormat.replace('%M', 'mm') fieldFormat = fieldFormat.replace('%-M', 'm') fieldFormat = fieldFormat.replace('%S', 'ss') fieldFormat = fieldFormat.replace('%-S', 's') fieldFormat = fieldFormat.replace('%f', 'zzz') fieldFormat = fieldFormat.replace('%p', 'AP') attrib['format'] = fieldFormat del attrib['fieldname'] return attrib def _convertOldPrintData(attrib): """Return old XML print data attributes from current print data. Arguments: attrib -- current print data attributes """ for key in ('printlines', 'printwidowcontrol', 'printportrait'): if key in attrib and not attrib[key]: attrib[key] = 'n' for key in ('printindentfactor', 'printpaperwidth', 'printpaperheight', 'printheadermargin', 'printfootermargin', 'printcolumnspace', 'printnumcolumns'): if key in attrib: attrib[key] = repr(attrib[key]) if 'printmargins' in attrib: attrib['printmargins'] = ' '.join([repr(margin) for margin in attrib['printmargins']]) return attrib def _createGenericXml(node, addChildren=True): """Return an ElementTree element with generic XML from this branch. Called recursively for children if addChildren is True. Arguments: node -- the node to export addChildren -- add branch if True """ nodeFormat = node.formatRef element = ElementTree.Element(nodeFormat.name) element.tail = '\n' for fieldName in nodeFormat.fieldNames(): text = node.data.get(fieldName, '') if text and fieldName != imports.genericXmlTextFieldName: element.set(fieldName, text) if imports.genericXmlTextFieldName in nodeFormat.fieldDict: text = node.data.get(imports.genericXmlTextFieldName, '') if text: element.text = text if addChildren and node.childList: if not text: element.text = '\n' for child in node.childList: element.append(_createGenericXml(child)) return element def _addElemToZip(destZip, rootElem, fileName): """Adds ElementTree root elements to the given zip file. Arguments: destZip -- the destination zip file rootElem -- the root element tree item to add fileName -- the file name or path in the zip file """ elemTree = ElementTree.ElementTree(rootElem) with io.BytesIO() as output: elemTree.write(output, 'utf-8', True) destZip.writestr(fileName, output.getvalue()) def _addOdfElement(name, parent=None, attr=None): """Shortcut function to add elements to the ElementTree. Converts names and attr keys from short version (with ':') to the full URI. Returns the new element. Arguments: name -- the element tag parent -- new element is added here if given attr -- a dict of the element's attrbutes """ if ':' in name: prefix, name = name.split(':', 1) name = '{{{0}}}{1}'.format(_odfNamespace[prefix], name) newAttr = {} if attr: for key, value in attr.items(): if ':' in key: prefix, key = key.split(':', 1) key = '{{{0}}}{1}'.format(_odfNamespace[prefix], key) newAttr[key] = value elem = ElementTree.Element(name, newAttr) elem.tail = '\n' if parent is not None: parent.append(elem) return elem def _addOdfText(spot, parentElem, addChildren=True, level=1, maxLevel=1): """Add heading and text elements to the parent element tree element. Called recursively for children if addChildren is True. Returns the maximum indent level used for this branch. Arguments: spot -- the spot to export parentElem -- the parent element tree element to add to addChildren -- add branch if True level -- the current tree indent level maxLevel -- the previous max indent level """ headElem = _addOdfElement('text:h', parentElem, {'text:outline-level': '{0}'.format(level), 'text:style-name': 'Heading_20_{0}'.format(level)}) headElem.text = spot.nodeRef.title(spot) output = spot.nodeRef.output(True, False, spot) if output and output[0] == spot.nodeRef.title(spot): del output[0] # remove first line if same as title for line in output: textElem = _addOdfElement('text:p', parentElem, {'text:outline-level': '{0}'.format(level), 'text:style-name': 'Text_20_body'}) textElem.text = line if addChildren and spot.nodeRef.childList: for child in spot.childSpots(): childlevel = _addOdfText(child, parentElem, True, level + 1, maxLevel) maxLevel = max(childlevel, maxLevel) else: maxLevel = max(level, maxLevel) return maxLevel def _exportHtmlBookmarks(node, addChildren=True): """Return a text list ith descendant bookmarks in Mozilla format. Called recursively for children if addChildren is True. Arguments: node -- the node to export addChildren -- add branch if True """ title = node.title() if not node.childList: nodeFormat = node.formatRef field = _findLinkField(nodeFormat) if field: linkMatch = fieldformat.linkRegExp.search(node.data. get(field.name, '')) if linkMatch: link = linkMatch.group(1) return ['
    {1}'.format(link, title)] elif (len(nodeFormat.fieldDict) == 1 and not node.data.get(nodeFormat.fieldNames()[0], '')): return ['
    '] result = ['

    {0}

    '.format(title)] if addChildren: result.append('

    ') for child in node.childList: result.extend(_exportHtmlBookmarks(child)) result.append('

    ') return result def _exportXbel(node, addChildren=True): """Return an ElementTree element with XBEL bookmarks from this branch. Called recursively for children if addChildren is True. Arguments: node -- the node to export addChildren -- add branch if True """ titleElem = ElementTree.Element('title') titleElem.text = node.title() if not node.childList: nodeFormat = node.formatRef field = _findLinkField(nodeFormat) if field: linkMatch = fieldformat.linkRegExp.search(node.data. get(field.name, '')) if linkMatch: link = linkMatch.group(1) element = ElementTree.Element('bookmark', {'href': link}) element.append(titleElem) element.tail = '\n' return element elif (len(nodeFormat.fieldDict) == 1 and not node.data.get(nodeFormat.fieldNames()[0], '')): element = ElementTree.Element('separator') element.tail = '\n' return element element = ElementTree.Element('folder') element.append(titleElem) element.tail = '\n' if addChildren: for child in node.childList: element.append(_exportXbel(child)) return element def _findLinkField(nodeFormat): """Return the field most likely to contain a bookmark URL. Return None if there are no matches. Arguments: nodeFormat -- the format to find a field in """ availFields = [field for field in nodeFormat.fieldDict.values() if field.typeName == 'ExternalLink'] if not availFields: return None bestFields = [field for field in availFields if field.name.lower() == imports.bookmarkLinkFieldName.lower()] if bestFields: return bestFields[0] return availFields[0] class ExportDialog(QWizard): """Dialog/wizard for setting file export type and options. """ typePage, subtypePage, optionPage = range(3) entireTree, selectBranch, selectNode = range(3) exportWhat = entireTree includeRoot = False openOnly = False addHeader = False numColumns = 1 navPaneLevels = 2 exportTypes = ['html', 'text', 'treeline', 'xml', 'odf', 'bookmarks'] currentType = 'html' exportTypeDescript = {'html': _('&HTML'), 'text': _('&Text'), 'treeline': _('Tree&Line'), 'xml': _('&XML (generic)'), 'odf': _('&ODF Outline'), 'bookmarks': _('Book&marks')} exportSubtypes = {'html': ['htmlSingle', 'htmlNavSingle','htmlPages', 'htmlTables', 'htmlLiveLink', 'htmlLiveSingle'], 'text': ['textTitles', 'textPlain', 'textTableMultiCsv', 'textTableCsv', 'textTableTab'], 'treeline': ['oldTreeLine', 'treeLineSubtree'], 'xml': ['xmlGeneric'], 'odf': ['odfText'], 'bookmarks': ['bookmarksHtml', 'bookmarksXbel']} currentSubtype = 'htmlSingle' subtypeDescript = {'htmlSingle': _('&Single HTML page'), 'htmlNavSingle': _('Single &HTML page with ' 'navigation pane'), 'htmlPages': _('Multiple HTML &pages with ' 'navigation pane'), 'htmlTables': _('Multiple HTML &data tables'), 'htmlLiveLink': _('Live tree view, linked to ' 'TreeLine file (for web server)'), 'htmlLiveSingle': _('Live tree view, single file ' '(embedded data)'), 'textTitles': _('&Tabbed title text'), 'textPlain': _('&Unformatted output of all text'), 'textTableMultiCsv': _('&Comma delimited (CSV) table ' 'of descendants (level numbers)'), 'textTableCsv': _('Comma &delimited (CSV) table ' 'of children (single level)'), 'textTableTab': _('Tab &delimited table of children ' '(&single level)'), 'oldTreeLine': _('&Old TreeLine (2.0.x)'), 'treeLineSubtree': _('&TreeLine Subtree'), 'bookmarksHtml': _('&HTML format bookmarks'), 'bookmarksXbel': _('&XBEL format bookmarks')} disableEntireTree = {'textTableCsv', 'textTableTab', 'treeLineSubtree'} disableSelBranches = {'htmlLiveLink'} disableSelNodes = {'htmlNavSingle', 'htmlPages', 'htmlTables', 'htmlLiveLink', 'textTableMultiCsv'} enableRootNode = {'htmlSingle', 'htmlNavSingle', 'textTitles', 'textPlain', 'textTableMultiCsv', 'ODF'} forceRootNodeOff = {'textTableCsv', 'textTableTab'} enableOpenOnly = {'htmlSingle', 'htmlNavSingle', 'textTitles', 'textPlain', 'textTableMultiCsv', 'ODF'} enableHeader = {'htmlSingle', 'htmlNavSingle', 'htmlTables'} enableColumns = {'htmlSingle'} enableNavLevels = {'htmlNavSingle'} def __init__(self, selectionAvail=True, parent=None): """Initialize the export wizard. Arguments: selectionAvail -- false if no nodes or branches are selected parent -- the parent window """ super().__init__(parent, Qt.WindowType.Dialog) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('File Export')) self.setWizardStyle(QWizard.WizardStyle.ClassicStyle) self.setPage(ExportDialog.typePage, ExportDialogTypePage()) self.setPage(ExportDialog.subtypePage, ExportDialogSubtypePage()) self.setPage(ExportDialog.optionPage, ExportDialogOptionPage(selectionAvail)) class ExportDialogTypePage(QWizardPage): """A wizard page for selecting the main export type. """ def __init__(self, parent=None): """Initialize the export wizard page. Arguments: parent -- parent widget, set automatically by addPage or setPage """ super().__init__(parent) topLayout = QVBoxLayout(self) self.setLayout(topLayout) self.setTitle(_('Choose export format type')) typeButtons = QButtonGroup(self) for id, exportType in enumerate(ExportDialog.exportTypes): button = QRadioButton(ExportDialog. exportTypeDescript[exportType]) typeButtons.addButton(button, id) topLayout.addWidget(button) if exportType == ExportDialog.currentType: button.setChecked(True) typeButtons.idClicked.connect(self.setCurrentType) def setCurrentType(self, buttonID): """Set the saved current type value based on a button click. Also sets the subtype to a default value. Arguments: buttonId -- the ID number of the button that was clicked """ ExportDialog.currentType = ExportDialog.exportTypes[buttonID] ExportDialog.currentSubtype = (ExportDialog. exportSubtypes[ExportDialog.currentType][0]) def nextId(self): """Return the ID for the next page in the wizard sequence. """ if len(ExportDialog.exportSubtypes[ExportDialog.currentType]) > 1: return ExportDialog.subtypePage return ExportDialog.optionPage class ExportDialogSubtypePage(QWizardPage): """A wizard page for selecting the export subtype. """ def __init__(self, parent=None): """Initialize the export wizard page. Arguments: parent -- parent widget, set automatically by addPage or setPage """ super().__init__(parent) topLayout = QVBoxLayout(self) self.setLayout(topLayout) self.setTitle(_('Choose export format subtype')) self.subtypeButtons = QButtonGroup(self) self.subtypeButtons.idClicked.connect(self.setCurrentSubtype) def initializePage(self): """Add buttons to this page based on current settings. """ topLayout = self.layout() # remove old buttons from a previously set subtype for button in self.subtypeButtons.buttons(): self.subtypeButtons.removeButton(button) topLayout.removeWidget(button) button.deleteLater() for id, subtype in enumerate(ExportDialog. exportSubtypes[ExportDialog.currentType]): button = QRadioButton(ExportDialog.subtypeDescript[subtype]) self.subtypeButtons.addButton(button, id) topLayout.addWidget(button) if subtype == ExportDialog.currentSubtype: button.setChecked(True) def setCurrentSubtype(self, buttonId): """Set the saved current subtype value based on a button click. Arguments: buttonId -- the ID number of the button that was clicked """ availSubtypes = ExportDialog.exportSubtypes[ExportDialog.currentType] ExportDialog.currentSubtype = availSubtypes[buttonId] class ExportDialogOptionPage(QWizardPage): """A wizard page for selecting other export options. """ def __init__(self, selectionAvail=True, parent=None): """Initialize the export wizard page. Arguments: selectionAvail -- false if no nodes or branches are selected parent -- parent widget, set automatically by addPage or setPage """ super().__init__(parent) self.selectionAvail = selectionAvail topLayout = QVBoxLayout(self) self.setLayout(topLayout) self.setTitle(_('Choose export options')) whatGroupBox = QGroupBox(_('What to Export')) topLayout.addWidget(whatGroupBox) whatLayout = QVBoxLayout(whatGroupBox) self.whatButtons = QButtonGroup(self) treeButton = QRadioButton(_('&Entire tree')) self.whatButtons.addButton(treeButton, ExportDialog.entireTree) whatLayout.addWidget(treeButton) branchButton = QRadioButton(_('Selected &branches')) self.whatButtons.addButton(branchButton, ExportDialog.selectBranch) whatLayout.addWidget(branchButton) nodeButton = QRadioButton(_('Selected &nodes')) self.whatButtons.addButton(nodeButton, ExportDialog.selectNode) whatLayout.addWidget(nodeButton) self.whatButtons.button(ExportDialog.exportWhat).setChecked(True) self.whatButtons.idClicked.connect(self.setExportWhat) optionBox = QGroupBox(_('Other Options')) topLayout.addWidget(optionBox) optionLayout = QVBoxLayout(optionBox) self.rootButton = QCheckBox(_('&Include root nodes')) optionLayout.addWidget(self.rootButton) self.rootButton.setChecked(ExportDialog.includeRoot) self.rootButton.toggled.connect(self.setIncludeRoot) self.openOnlyButton = QCheckBox(_('&Only open node children')) optionLayout.addWidget(self.openOnlyButton) self.openOnlyButton.setChecked(ExportDialog.openOnly) self.openOnlyButton.toggled.connect(self.setOpenOnly) self.headerButton = QCheckBox(_('Include &print header && ' 'footer')) optionLayout.addWidget(self.headerButton) self.headerButton.setChecked(ExportDialog.addHeader) self.headerButton.toggled.connect(self.setAddHeader) columnLayout = QHBoxLayout() optionLayout.addLayout(columnLayout) self.numColSpin = QSpinBox() columnLayout.addWidget(self.numColSpin) self.numColSpin.setRange(1, 9) self.numColSpin.setMaximumWidth(40) self.numColSpin.setValue(ExportDialog.numColumns) self.colLabel = QLabel(_('&Columns')) columnLayout.addWidget(self.colLabel) self.colLabel.setBuddy(self.numColSpin) self.numColSpin.valueChanged.connect(self.setNumColumns) navLevelsLayout = QHBoxLayout() optionLayout.addLayout(navLevelsLayout) self.navLevelsSpin = QSpinBox() navLevelsLayout.addWidget(self.navLevelsSpin) self.navLevelsSpin.setRange(1, 9) self.navLevelsSpin.setMaximumWidth(40) self.navLevelsSpin.setValue(ExportDialog.navPaneLevels) self.navLevelsLabel = QLabel(_('Navigation pane &levels')) navLevelsLayout.addWidget(self.navLevelsLabel) self.navLevelsLabel.setBuddy(self.navLevelsSpin) self.navLevelsSpin.valueChanged.connect(self.setNavLevels) def initializePage(self): """Enable or disable controls based on current settings. """ subtype = ExportDialog.currentSubtype treeButton, branchButton, nodeButton = self.whatButtons.buttons() treeButton.setEnabled(subtype not in ExportDialog.disableEntireTree) branchButton.setEnabled(subtype not in ExportDialog.disableSelBranches and self.selectionAvail) nodeButton.setEnabled(subtype not in ExportDialog.disableSelNodes and self.selectionAvail) num = 0 while not self.whatButtons.checkedButton().isEnabled(): try: self.whatButtons.button(num).setChecked(True) except AttributeError: QMessageBox.warning(self, 'TreeLine', _('Must select nodes prior to export')) parent = self.parent() while parent: try: parent.reject() return except AttributeError: parent = parent.parent() num += 1 if (subtype in ExportDialog.enableRootNode and ExportDialog.exportWhat != ExportDialog.selectNode): self.rootButton.setEnabled(True) self.rootButton.setChecked(ExportDialog.includeRoot) else: self.rootButton.setEnabled(False) self.rootButton.setChecked(subtype not in ExportDialog.forceRootNodeOff) if (subtype in ExportDialog.enableOpenOnly and ExportDialog.exportWhat != ExportDialog.selectNode): self.openOnlyButton.setEnabled(True) else: self.openOnlyButton.setEnabled(False) self.openOnlyButton.setChecked(False) self.headerButton.setEnabled(subtype in ExportDialog.enableHeader) if subtype not in ExportDialog.enableHeader: self.headerButton.setChecked(False) columnsEnabled = subtype in ExportDialog.enableColumns self.numColSpin.setVisible(columnsEnabled) self.colLabel.setVisible(columnsEnabled) if not columnsEnabled: self.numColSpin.setValue(1) navLevelsEnabled = subtype in ExportDialog.enableNavLevels self.navLevelsSpin.setVisible(navLevelsEnabled) self.navLevelsLabel.setVisible(navLevelsEnabled) def setExportWhat(self, buttonNum): """Set what to export (all, branch, node) based on button group click. Arguments: buttonNum -- the ID number of the clicked button """ ExportDialog.exportWhat = buttonNum self.initializePage() def setIncludeRoot(self, checked): """Set whether root node is included based on a button click. Arguments: checked -- True if the check box is checked """ ExportDialog.includeRoot = checked def setOpenOnly(self, checked): """Set whether only open nodes are included based on a button click. Arguments: checked -- True if the check box is checked """ ExportDialog.openOnly = checked def setAddHeader(self, checked): """Set whether headers and footers are added based on a button click. Arguments: checked -- True if the check box is checked """ ExportDialog.addHeader = checked def setNumColumns(self, num): """Set number of columns based on a spin box change. Arguments: num -- the new spin box setting """ ExportDialog.numColumns = num def setNavLevels(self, num): """Set number of navigation pane levels based on a spin box change. Arguments: num -- the new spin box setting """ ExportDialog.navPaneLevels = num TreeLine-3.2.1/source/fieldformat.py000066400000000000000000002752721506556630100174200ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # fieldformat.py, provides a class to handle field format types # # TreeLine, an information storage program # Copyright (C) 2023, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import sys import enum import datetime import xml.sax.saxutils as saxutils import gennumber import genboolean import numbering import matheval import urltools import globalref fieldTypes = [N_('Text'), N_('HtmlText'), N_('OneLineText'), N_('SpacedText'), N_('Number'), N_('Math'), N_('Numbering'), N_('Date'), N_('Time'), N_('DateTime'), N_('Boolean'), N_('Choice'), N_('AutoChoice'), N_('Combination'), N_('AutoCombination'), N_('ExternalLink'), N_('InternalLink'), N_('Picture'), N_('RegularExpression')] translatedFieldTypes = [_(name) for name in fieldTypes] _errorStr = '#####' _dateStampString = _('Now') _timeStampString = _('Now') MathResult = enum.Enum('MathResult', 'number date time boolean text') _mathResultBlank = {MathResult.number: 0, MathResult.date: 0, MathResult.time: 0, MathResult.boolean: False, MathResult.text: ''} _multipleSpaceRegEx = re.compile(r' {2,}') _lineBreakRegEx = re.compile(r'', re.I) _stripTagRe = re.compile(r'<.*?>') linkRegExp = re.compile(r']*href="([^"]+)"[^>]*>(.*?)', re.I | re.S) linkSeparateNameRegExp = re.compile(r'(.*) \[(.*)\]\s*$') _imageRegExp = re.compile(r']*src="([^"]+)"[^>]*>', re.I | re.S) class TextField: """Class to handle a rich-text field format type. Stores options and format strings for a text field type. Provides methods to return formatted data. """ typeName = 'Text' defaultFormat = '' showRichTextInCell = True evalHtmlDefault = False fixEvalHtmlSetting = True defaultNumLines = 1 editorClassName = 'RichTextEditor' sortTypeStr = '80_text' supportsInitDefault = True formatHelpMenuList = [] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ self.name = name if not formatData: formatData = {} self.prefix = formatData.get('prefix', '') self.suffix = formatData.get('suffix', '') self.initDefault = formatData.get('init', '') self.numLines = formatData.get('lines', type(self).defaultNumLines) self.sortKeyNum = formatData.get('sortkeynum', 0) self.sortKeyForward = formatData.get('sortkeyfwd', True) self.evalHtml = self.evalHtmlDefault if not self.fixEvalHtmlSetting: self.evalHtml = formatData.get('evalhtml', self.evalHtmlDefault) self.useFileInfo = False self.showInDialog = True self.setFormat(formatData.get('format', type(self).defaultFormat)) def formatData(self): """Return a dictionary of this field's format settings. """ formatData = {'fieldname': self.name, 'fieldtype': self.typeName} if self.format: formatData['format'] = self.format if self.prefix: formatData['prefix'] = self.prefix if self.suffix: formatData['suffix'] = self.suffix if self.initDefault: formatData['init'] = self.initDefault if self.numLines != self.defaultNumLines: formatData['lines'] = self.numLines if self.sortKeyNum > 0: formatData['sortkeynum'] = self.sortKeyNum if not self.sortKeyForward: formatData['sortkeyfwd'] = False if (not self.fixEvalHtmlSetting and self.evalHtml != self.evalHtmlDefault): formatData['evalhtml'] = self.evalHtml return formatData def setFormat(self, format): """Set the format string and initialize as required. Derived classes may raise a ValueError if the format is illegal. Arguments: format -- the new format string """ self.format = format def outputText(self, node, oneLine, noHtml, formatHtml, spotRef=None): """Return formatted output text for this field in this node. Arguments: node -- the tree item storing the data oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix spotRef -- optional, used for ancestor field refs """ if self.useFileInfo and node.spotRefs: # get file info node if not already the file info node node = node.treeStructureRef().fileInfoNode storedText = node.data.get(self.name, '') if storedText: return self.formatOutput(storedText, oneLine, noHtml, formatHtml) return '' def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ prefix = self.prefix suffix = self.suffix if oneLine: storedText = _lineBreakRegEx.split(storedText, 1)[0] if noHtml: storedText = removeMarkup(storedText) if formatHtml: prefix = removeMarkup(prefix) suffix = removeMarkup(suffix) if not formatHtml: prefix = saxutils.escape(prefix) suffix = saxutils.escape(suffix) return '{0}{1}{2}'.format(prefix, storedText, suffix) def editorText(self, node): """Return text formatted for use in the data editor. The function for default text just returns the stored text. Overloads may raise a ValueError if the data does not match the format. Arguments: node -- the tree item storing the data """ storedText = node.data.get(self.name, '') return self.formatEditorText(storedText) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. The function for default text just returns the stored text. Overloads may raise a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ return storedText def storedText(self, editorText): """Return new text to be stored based on text from the data editor. The function for default text field just returns the editor text. Overloads may raise a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ return editorText def storedTextFromTitle(self, titleText): """Return new text to be stored based on title text edits. Overloads may raise a ValueError if the data does not match the format. Arguments: titleText -- the new title text """ return self.storedText(saxutils.escape(titleText)) def getInitDefault(self): """Return the initial stored value for newly created nodes. """ return self.initDefault def setInitDefault(self, editorText): """Set the default initial value from editor text. The function for default text field just returns the stored text. Arguments: editorText -- the new text entered into the editor """ self.initDefault = self.storedText(editorText) def getEditorInitDefault(self): """Return initial value in editor format. """ value = '' if self.supportsInitDefault: try: value = self.formatEditorText(self.initDefault) except ValueError: pass return value def initDefaultChoices(self): """Return a list of choices for setting the init default. """ return [] def mathValue(self, node, zeroBlanks=True, noMarkup=True): """Return a value to be used in math field equations. Return None if blank and not zeroBlanks. Arguments: node -- the tree item storing the data zeroBlanks -- accept blank field values if True noMarkup -- if true, remove html markup """ storedText = node.data.get(self.name, '') if storedText and noMarkup: storedText = removeMarkup(storedText) return storedText if storedText or zeroBlanks else None def compareValue(self, node): """Return a value for comparison to other nodes and for sorting. Returns lowercase text for text fields or numbers for non-text fields. Arguments: node -- the tree item storing the data """ storedText = node.data.get(self.name, '') return self.adjustedCompareValue(storedText) def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Text version removes any markup and goes to lower case. Arguments: value -- the comparison value to adjust """ value = removeMarkup(value) return value.lower() def sortKey(self, node): """Return a tuple with field type and comparison value for sorting. Allows different types to be sorted. Arguments: node -- the tree item storing the data """ return (self.sortTypeStr, self.compareValue(node)) def changeType(self, newType): """Change this field's type to newType with a default format. Arguments: newType -- the new type name, excluding "Field" """ oldType = self.typeName self.__class__ = globals()[newType + 'Field'] # Don't lose format between Choice & Combination types if (oldType not in ('Choice', 'Combination') or newType not in ('Choice', 'Combination') or not self.format): self.setFormat(self.defaultFormat) if self.fixEvalHtmlSetting: self.evalHtml = self.evalHtmlDefault def sepName(self): """Return the name enclosed with {* *} separators """ if self.useFileInfo: return '{{*!{0}*}}'.format(self.name) return '{{*{0}*}}'.format(self.name) def getFormatHelpMenuList(self): """Return the list of descriptions and keys for the format help menu. """ return self.formatHelpMenuList class HtmlTextField(TextField): """Class to handle an HTML text field format type Stores options and format strings for an HTML text field type. Does not use the rich text editor. Provides methods to return formatted data. """ typeName = 'HtmlText' showRichTextInCell = False evalHtmlDefault = True editorClassName = 'HtmlTextEditor' def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def storedTextFromTitle(self, titleText): """Return new text to be stored based on title text edits. Overloads may raise a ValueError if the data does not match the format. Arguments: titleText -- the new title text """ return self.storedText(titleText) class OneLineTextField(TextField): """Class to handle a single-line rich-text field format type. Stores options and format strings for a text field type. Provides methods to return formatted data. """ typeName = 'OneLineText' editorClassName = 'OneLineTextEditor' def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ text = _lineBreakRegEx.split(storedText, 1)[0] return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ return _lineBreakRegEx.split(storedText, 1)[0] class SpacedTextField(TextField): """Class to handle a preformatted text field format type. Stores options and format strings for a spaced text field type. Uses

     tags to preserve spacing.
        Does not use the rich text editor.
        Provides methods to return formatted data.
        """
        typeName = 'SpacedText'
        showRichTextInCell = False
        editorClassName = 'PlainTextEditor'
        def __init__(self, name, formatData=None):
            """Initialize a field format type.
    
            Arguments:
                name -- the field name string
                formatData -- the dict that defines this field's format
            """
            super().__init__(name, formatData)
    
        def formatOutput(self, storedText, oneLine, noHtml, formatHtml):
            """Return formatted output text from stored text for this field.
    
            Arguments:
                storedText -- the source text to format
                oneLine -- if True, returns only first line of output (for titles)
                noHtml -- if True, removes all HTML markup (for titles, etc.)
                formatHtml -- if False, escapes HTML from prefix & suffix
            """
            if storedText:
                storedText = '
    {0}
    '.format(storedText) return super().formatOutput(storedText, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Arguments: storedText -- the source text to format """ return saxutils.unescape(storedText) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Arguments: editorText -- the new text entered into the editor """ return saxutils.escape(editorText) def storedTextFromTitle(self, titleText): """Return new text to be stored based on title text edits. Arguments: titleText -- the new title text """ return self.storedText(titleText) class NumberField(HtmlTextField): """Class to handle a general number field format type. Stores options and format strings for a number field type. Provides methods to return formatted data. """ typeName = 'Number' defaultFormat = '#.##' evalHtmlDefault = False editorClassName = 'LineEditor' sortTypeStr = '20_num' formatHelpMenuList = [(_('Optional Digit\t#'), '#'), (_('Required Digit\t0'), '0'), (_('Digit or Space (external)\t'), ' '), ('', ''), (_('Decimal Point\t.'), '.'), (_('Decimal Comma\t,'), ','), ('', ''), (_('Comma Separator\t\\,'), '\\,'), (_('Dot Separator\t\\.'), '\\.'), (_('Space Separator (internal)\t'), ' '), ('', ''), (_('Optional Sign\t-'), '-'), (_('Required Sign\t+'), '+'), ('', ''), (_('Exponent (capital)\tE'), 'E'), (_('Exponent (small)\te'), 'e')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ try: text = gennumber.GenNumber(storedText).numStr(self.format) except ValueError: text = _errorStr return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' return gennumber.GenNumber(storedText).numStr(self.format) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ if not editorText: return '' return repr(gennumber.GenNumber().setFromStr(editorText, self.format)) def mathValue(self, node, zeroBlanks=True, noMarkup=True): """Return a numeric value to be used in math field equations. Return None if blank and not zeroBlanks, raise a ValueError if it isn't a number. Arguments: node -- the tree item storing the data zeroBlanks -- replace blank field values with zeros if True noMarkup -- not applicable to numbers """ storedText = node.data.get(self.name, '') if storedText: return gennumber.GenNumber(storedText).num return 0 if zeroBlanks else None def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Number version converts to a numeric value. Arguments: value -- the comparison value to adjust """ try: return gennumber.GenNumber(value).num except ValueError: return 0 class MathField(HtmlTextField): """Class to handle a math calculation field type. Stores options and format strings for a math field type. Provides methods to return formatted data. """ typeName = 'Math' defaultFormat = '#.##' evalHtmlDefault = False fixEvalHtmlSetting = False editorClassName = 'ReadOnlyEditor' def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ super().__init__(name, formatData) self.equation = None self.resultType = MathResult[formatData.get('resulttype', 'number')] equationText = formatData.get('eqn', '').strip() if equationText: self.equation = matheval.MathEquation(equationText) try: self.equation.validate() except ValueError: self.equation = None def formatData(self): """Return a dictionary of this field's attributes. Add the math equation to the standard XML output. """ formatData = super().formatData() if self.equation: formatData['eqn'] = self.equation.equationText() if self.resultType != MathResult.number: formatData['resulttype'] = self.resultType.name return formatData def setFormat(self, format): """Set the format string and initialize as required. Arguments: format -- the new format string """ if not hasattr(self, 'equation'): self.equation = None self.resultType = MathResult.number super().setFormat(format) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ text = storedText try: if self.resultType == MathResult.number: text = gennumber.GenNumber(text).numStr(self.format) elif self.resultType == MathResult.date: date = datetime.datetime.strptime(text, DateField.isoFormat).date() text = date.strftime(adjOutDateFormat(self.format)) elif self.resultType == MathResult.time: time = datetime.datetime.strptime(text, TimeField.isoFormat).time() text = time.strftime(adjOutDateFormat(self.format)) elif self.resultType == MathResult.boolean: text = genboolean.GenBoolean(text).boolStr(self.format) except ValueError: text = _errorStr return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' if self.resultType == MathResult.number: return gennumber.GenNumber(storedText).numStr(self.format) if self.resultType == MathResult.date: date = datetime.datetime.strptime(storedText, DateField.isoFormat).date() editorFormat = adjOutDateFormat(globalref. genOptions['EditDateFormat']) return date.strftime(editorFormat) if self.resultType == MathResult.time: time = datetime.datetime.strptime(storedText, TimeField.isoFormat).time() editorFormat = adjOutDateFormat(globalref. genOptions['EditTimeFormat']) return time.strftime(editorFormat) if self.resultType == MathResult.boolean: return genboolean.GenBoolean(storedText).boolStr(self.format) if storedText == _errorStr: raise ValueError return storedText def equationText(self): """Return the current equation text. """ if self.equation: return self.equation.equationText() return '' def equationValue(self, node): """Return a text value from the result of the equation. Returns the '#####' error string for illegal math operations. Arguments: node -- the tree item with this equation """ if self.equation: zeroValue = _mathResultBlank[self.resultType] try: num = self.equation.equationValue(node, self.resultType, zeroValue, not self.evalHtml) except ValueError: return _errorStr if num == None: return '' if self.resultType == MathResult.date: date = DateField.refDate + datetime.timedelta(days=num) return date.strftime(DateField.isoFormat) if self.resultType == MathResult.time: dateTime = datetime.datetime.combine(DateField.refDate, TimeField.refTime) dateTime = dateTime + datetime.timedelta(seconds=num) time = dateTime.time() return time.strftime(TimeField.isoFormat) text = str(num) if not self.evalHtml: text = saxutils.escape(text) return text return '' def resultClass(self): """Return the result type's field class. """ return globals()[self.resultType.name.capitalize() + 'Field'] def changeResultType(self, resultType): """Change the result type and reset the output format. Arguments: resultType -- the new result type """ if resultType != self.resultType: self.resultType = resultType self.setFormat(self.resultClass().defaultFormat) def mathValue(self, node, zeroBlanks=True, noMarkup=True): """Return a numeric value to be used in math field equations. Return None if blank and not zeroBlanks, raise a ValueError if it isn't valid. Arguments: node -- the tree item storing the data zeroBlanks -- replace blank field values with zeros if True noMarkup -- if true, remove html markup """ storedText = node.data.get(self.name, '') if storedText: if self.resultType == MathResult.number: return gennumber.GenNumber(storedText).num if self.resultType == MathResult.date: date = datetime.datetime.strptime(storedText, DateField.isoFormat).date() return (date - DateField.refDate).days if self.resultType == MathResult.time: time = datetime.datetime.strptime(storedText, TimeField.isoFormat).time() return (time - TimeField.refTime).seconds if self.resultType == MathResult.boolean: return genboolean.GenBoolean(storedText).value if noMarkup: storedText = removeMarkup(storedText) return storedText return _mathResultBlank[self.resultType] if zeroBlanks else None def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Number version converts to a numeric value. Arguments: value -- the comparison value to adjust """ try: if self.resultType == MathResult.number: return gennumber.GenNumber(value).num if self.resultType == MathResult.date: date = datetime.datetime.strptime(value, DateField.isoFormat).date() return date.strftime(DateField.isoFormat) if self.resultType == MathResult.time: time = datetime.datetime.strptime(value, TimeField.isoFormat).time() return time.strftime(TimeField.isoFormat) if self.resultType == MathResult.boolean: return genboolean.GenBoolean(value).value return value.lower() except ValueError: return 0 def sortKey(self, node): """Return a tuple with field type and comparison value for sorting. Allows different types to be sorted. Arguments: node -- the tree item storing the data """ return (self.resultClass().sortTypeStr, self.compareValue(node)) def getFormatHelpMenuList(self): """Return the list of descriptions and keys for the format help menu. """ return self.resultClass().formatHelpMenuList class NumberingField(HtmlTextField): """Class to handle formats for hierarchical node numbering. Stores options and format strings for a node numbering field type. Provides methods to return formatted node numbers. """ typeName = 'Numbering' defaultFormat = '1..' evalHtmlDefault = False editorClassName = 'LineEditor' sortTypeStr = '10_numbering' formatHelpMenuList = [(_('Number\t1'), '1'), (_('Capital Letter\tA'), 'A'), (_('Small Letter\ta'), 'a'), (_('Capital Roman Numeral\tI'), 'I'), (_('Small Roman Numeral\ti'), 'i'), ('', ''), (_('Level Separator\t/'), '/'), (_('Section Separator\t.'), '.'), ('', ''), (_('"/" Character\t//'), '//'), (_('"." Character\t..'), '..'), ('', ''), (_('Outline Example\tI../A../1../a)/i)'), 'I../A../1../a)/i)'), (_('Section Example\t1.1.1.1'), '1.1.1.1')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ self.numFormat = None super().__init__(name, formatData) def setFormat(self, format): """Set the format string and initialize as required. Arguments: format -- the new format string """ self.numFormat = numbering.NumberingGroup(format) super().setFormat(format) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ try: text = self.numFormat.numString(storedText) except ValueError: text = _errorStr return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if storedText: checkData = [int(num) for num in storedText.split('.')] return storedText def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ if editorText: checkData = [int(num) for num in editorText.split('.')] return editorText def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Number version converts to a numeric value. Arguments: value -- the comparison value to adjust """ if value: try: return [int(num) for num in value.split('.')] except ValueError: pass return [0] class DateField(HtmlTextField): """Class to handle a general date field format type. Stores options and format strings for a date field type. Provides methods to return formatted data. """ typeName = 'Date' defaultFormat = '%B %-d, %Y' isoFormat = '%Y-%m-%d' evalHtmlDefault = False fixEvalHtmlSetting = False editorClassName = 'DateEditor' refDate = datetime.date(1970, 1, 1) sortTypeStr = '40_date' formatHelpMenuList = [(_('Day (1 or 2 digits)\t%-d'), '%-d'), (_('Day (2 digits)\t%d'), '%d'), ('', ''), (_('Weekday Abbreviation\t%a'), '%a'), (_('Weekday Name\t%A'), '%A'), ('', ''), (_('Month (1 or 2 digits)\t%-m'), '%-m'), (_('Month (2 digits)\t%m'), '%m'), (_('Month Abbreviation\t%b'), '%b'), (_('Month Name\t%B'), '%B'), ('', ''), (_('Year (2 digits)\t%y'), '%y'), (_('Year (4 digits)\t%Y'), '%Y'), ('', ''), (_('Week Number (0 to 53)\t%-U'), '%-U'), (_('Day of year (1 to 366)\t%-j'), '%-j')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ try: date = datetime.datetime.strptime(storedText, DateField.isoFormat).date() text = date.strftime(adjOutDateFormat(self.format)) except ValueError: text = _errorStr if not self.evalHtml: text = saxutils.escape(text) return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' date = datetime.datetime.strptime(storedText, DateField.isoFormat).date() editorFormat = adjOutDateFormat(globalref.genOptions['EditDateFormat']) return date.strftime(editorFormat) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Two digit years are interpretted as 1950-2049. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ editorText = _multipleSpaceRegEx.sub(' ', editorText.strip()) if not editorText: return '' editorFormat = adjInDateFormat(globalref.genOptions['EditDateFormat']) try: date = datetime.datetime.strptime(editorText, editorFormat).date() except ValueError: # allow use of a 4-digit year to fix invalid dates fullYearFormat = editorFormat.replace('%y', '%Y') if fullYearFormat != editorFormat: date = datetime.datetime.strptime(editorText, fullYearFormat).date() else: raise return date.strftime(DateField.isoFormat) def getInitDefault(self): """Return the initial stored value for newly created nodes. """ if self.initDefault == _dateStampString: date = datetime.date.today() return date.strftime(DateField.isoFormat) return super().getInitDefault() def setInitDefault(self, editorText): """Set the default initial value from editor text. The function for default text field just returns the stored text. Arguments: editorText -- the new text entered into the editor """ if editorText == _dateStampString: self.initDefault = _dateStampString else: super().setInitDefault(editorText) def getEditorInitDefault(self): """Return initial value in editor format. """ if self.initDefault == _dateStampString: return _dateStampString return super().getEditorInitDefault() def initDefaultChoices(self): """Return a list of choices for setting the init default. """ return [_dateStampString] def mathValue(self, node, zeroBlanks=True, noMarkup=True): """Return a numeric value to be used in math field equations. Return None if blank and not zeroBlanks, raise a ValueError if it isn't a valid date. Arguments: node -- the tree item storing the data zeroBlanks -- replace blank field values with zeros if True """ storedText = node.data.get(self.name, '') if storedText: date = datetime.datetime.strptime(storedText, DateField.isoFormat).date() return (date - DateField.refDate).days return 0 if zeroBlanks else None def compareValue(self, node): """Return a value for comparison to other nodes and for sorting. Returns lowercase text for text fields or numbers for non-text fields. Date field uses ISO date format (YYY-MM-DD). Arguments: node -- the tree item storing the data """ return node.data.get(self.name, '') def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Date version converts to an ISO date format (YYYY-MM-DD). Arguments: value -- the comparison value to adjust """ value = _multipleSpaceRegEx.sub(' ', value.strip()) if not value: return '' if value == _dateStampString: date = datetime.date.today() return date.strftime(DateField.isoFormat) try: return self.storedText(value) except ValueError: return value class TimeField(HtmlTextField): """Class to handle a general time field format type Stores options and format strings for a time field type. Provides methods to return formatted data. """ typeName = 'Time' defaultFormat = '%-I:%M:%S %p' isoFormat = '%H:%M:%S.%f' evalHtmlDefault = False fixEvalHtmlSetting = False editorClassName = 'TimeEditor' numChoiceColumns = 2 autoAddChoices = False refTime = datetime.time() sortTypeStr = '50_time' formatHelpMenuList = [(_('Hour (0-23, 1 or 2 digits)\t%-H'), '%-H'), (_('Hour (00-23, 2 digits)\t%H'), '%H'), (_('Hour (1-12, 1 or 2 digits)\t%-I'), '%-I'), (_('Hour (01-12, 2 digits)\t%I'), '%I'), ('', ''), (_('Minute (1 or 2 digits)\t%-M'), '%-M'), (_('Minute (2 digits)\t%M'), '%M'), ('', ''), (_('Second (1 or 2 digits)\t%-S'), '%-S'), (_('Second (2 digits)\t%S'), '%S'), ('', ''), (_('Microseconds (6 digits)\t%f'), '%f'), ('', ''), (_('AM/PM\t%p'), '%p')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ super().__init__(name, formatData) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ try: time = datetime.datetime.strptime(storedText, TimeField.isoFormat).time() outFormat = adjOutDateFormat(self.format) outFormat = adjTimeAmPm(outFormat, time) text = time.strftime(outFormat) except ValueError: text = _errorStr if not self.evalHtml: text = saxutils.escape(text) return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' time = datetime.datetime.strptime(storedText, TimeField.isoFormat).time() editorFormat = adjOutDateFormat(globalref.genOptions['EditTimeFormat']) editorFormat = adjTimeAmPm(editorFormat, time) return time.strftime(editorFormat) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ editorText = _multipleSpaceRegEx.sub(' ', editorText.strip()) if not editorText: return '' editorFormat = adjInDateFormat(globalref.genOptions['EditTimeFormat']) time = None try: time = datetime.datetime.strptime(editorText, editorFormat).time() except ValueError: noSecFormat = editorFormat.replace(':%S', '') noSecFormat = _multipleSpaceRegEx.sub(' ', noSecFormat.strip()) try: time = datetime.datetime.strptime(editorText, noSecFormat).time() except ValueError: for altFormat in (editorFormat, noSecFormat): noAmFormat = altFormat.replace('%p', '') noAmFormat = _multipleSpaceRegEx.sub(' ', noAmFormat.strip()) try: time = datetime.datetime.strptime(editorText, noAmFormat).time() break except ValueError: pass if not time: raise ValueError return time.strftime(TimeField.isoFormat) def annotatedComboChoices(self, editorText): """Return a list of (choice, annotation) tuples for the combo box. Arguments: editorText -- the text entered into the editor """ editorFormat = adjOutDateFormat(globalref.genOptions['EditTimeFormat']) choices = [(datetime.datetime.now().time().strftime(editorFormat), '({0})'.format(_timeStampString))] for hour in (6, 9, 12, 15, 18, 21, 0): choices.append((datetime.time(hour).strftime(editorFormat), '')) return choices def getInitDefault(self): """Return the initial stored value for newly created nodes. """ if self.initDefault == _timeStampString: time = datetime.datetime.now().time() return time.strftime(TimeField.isoFormat) return super().getInitDefault() def setInitDefault(self, editorText): """Set the default initial value from editor text. The function for default text field just returns the stored text. Arguments: editorText -- the new text entered into the editor """ if editorText == _timeStampString: self.initDefault = _timeStampString else: super().setInitDefault(editorText) def getEditorInitDefault(self): """Return initial value in editor format. """ if self.initDefault == _timeStampString: return _timeStampString return super().getEditorInitDefault() def initDefaultChoices(self): """Return a list of choices for setting the init default. """ return [_timeStampString] def mathValue(self, node, zeroBlanks=True, noMarkup=True): """Return a numeric value to be used in math field equations. Return None if blank and not zeroBlanks, raise a ValueError if it isn't a valid time. Arguments: node -- the tree item storing the data zeroBlanks -- replace blank field values with zeros if True """ storedText = node.data.get(self.name, '') if storedText: time = datetime.datetime.strptime(storedText, TimeField.isoFormat).time() dateTime = datetime.datetime.combine(DateField.refDate, time) refDateTime = datetime.datetime.combine(DateField.refDate, TimeField.refTime) return (dateTime - refDateTime).seconds return 0 if zeroBlanks else None def compareValue(self, node): """Return a value for comparison to other nodes and for sorting. Returns lowercase text for text fields or numbers for non-text fields. Time field uses HH:MM:SS format. Arguments: node -- the tree item storing the data """ return node.data.get(self.name, '') def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Time version converts to HH:MM:SS format. Arguments: value -- the comparison value to adjust """ value = _multipleSpaceRegEx.sub(' ', value.strip()) if not value: return '' if value == _timeStampString: time = datetime.datetime.now().time() return time.strftime(TimeField.isoFormat) try: return self.storedText(value) except ValueError: return value class DateTimeField(HtmlTextField): """Class to handle a general date and time field format type. Stores options and format strings for a date and time field type. Provides methods to return formatted data. """ typeName = 'DateTime' defaultFormat = '%B %-d, %Y %-I:%M:%S %p' isoFormat = '%Y-%m-%d %H:%M:%S.%f' evalHtmlDefault = False fixEvalHtmlSetting = False editorClassName = 'DateTimeEditor' refDateTime = datetime.datetime(1970, 1, 1) sortTypeStr ='45_datetime' formatHelpMenuList = [(_('Day (1 or 2 digits)\t%-d'), '%-d'), (_('Day (2 digits)\t%d'), '%d'), ('', ''), (_('Weekday Abbreviation\t%a'), '%a'), (_('Weekday Name\t%A'), '%A'), ('', ''), (_('Month (1 or 2 digits)\t%-m'), '%-m'), (_('Month (2 digits)\t%m'), '%m'), (_('Month Abbreviation\t%b'), '%b'), (_('Month Name\t%B'), '%B'), ('', ''), (_('Year (2 digits)\t%y'), '%y'), (_('Year (4 digits)\t%Y'), '%Y'), ('', ''), (_('Week Number (0 to 53)\t%-U'), '%-U'), (_('Day of year (1 to 366)\t%-j'), '%-j'), (_('Hour (0-23, 1 or 2 digits)\t%-H'), '%-H'), (_('Hour (00-23, 2 digits)\t%H'), '%H'), (_('Hour (1-12, 1 or 2 digits)\t%-I'), '%-I'), (_('Hour (01-12, 2 digits)\t%I'), '%I'), ('', ''), (_('Minute (1 or 2 digits)\t%-M'), '%-M'), (_('Minute (2 digits)\t%M'), '%M'), ('', ''), (_('Second (1 or 2 digits)\t%-S'), '%-S'), (_('Second (2 digits)\t%S'), '%S'), ('', ''), (_('Microseconds (6 digits)\t%f'), '%f'), ('', ''), (_('AM/PM\t%p'), '%p')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ try: dateTime = datetime.datetime.strptime(storedText, DateTimeField.isoFormat) outFormat = adjOutDateFormat(self.format) outFormat = adjTimeAmPm(outFormat, dateTime) text = dateTime.strftime(outFormat) except ValueError: text = _errorStr if not self.evalHtml: text = saxutils.escape(text) return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' dateTime = datetime.datetime.strptime(storedText, DateTimeField.isoFormat) editorFormat = '{0} {1}'.format(globalref.genOptions['EditDateFormat'], globalref.genOptions['EditTimeFormat']) editorFormat = adjOutDateFormat(editorFormat) editorFormat = adjTimeAmPm(editorFormat, dateTime) return dateTime.strftime(editorFormat) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Two digit years are interpretted as 1950-2049. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ editorText = _multipleSpaceRegEx.sub(' ', editorText.strip()) if not editorText: return '' editorFormat = '{0} {1}'.format(globalref.genOptions['EditDateFormat'], globalref.genOptions['EditTimeFormat']) editorFormat = adjInDateFormat(editorFormat) dateTime = None try: dateTime = datetime.datetime.strptime(editorText, editorFormat) except ValueError: noSecFormat = editorFormat.replace(':%S', '') noSecFormat = _multipleSpaceRegEx.sub(' ', noSecFormat.strip()) altFormats = [editorFormat, noSecFormat] for altFormat in altFormats[:]: noAmFormat = altFormat.replace('%p', '') noAmFormat = _multipleSpaceRegEx.sub(' ', noAmFormat.strip()) altFormats.append(noAmFormat) for altFormat in altFormats[:]: fullYearFormat = altFormat.replace('%y', '%Y') altFormats.append(fullYearFormat) for editorFormat in altFormats[1:]: try: dateTime = datetime.datetime.strptime(editorText, editorFormat) break except ValueError: pass if not dateTime: raise ValueError return dateTime.strftime(DateTimeField.isoFormat) def getInitDefault(self): """Return the initial stored value for newly created nodes. """ if self.initDefault == _timeStampString: dateTime = datetime.datetime.now() return dateTime.strftime(DateTimeField.isoFormat) return super().getInitDefault() def setInitDefault(self, editorText): """Set the default initial value from editor text. The function for default text field just returns the stored text. Arguments: editorText -- the new text entered into the editor """ if editorText == _timeStampString: self.initDefault = _timeStampString else: super().setInitDefault(editorText) def getEditorInitDefault(self): """Return initial value in editor format. """ if self.initDefault == _timeStampString: return _timeStampString return super().getEditorInitDefault() def initDefaultChoices(self): """Return a list of choices for setting the init default. """ return [_timeStampString] def mathValue(self, node, zeroBlanks=True, noMarkup=True): """Return a numeric value to be used in math field equations. Return None if blank and not zeroBlanks, raise a ValueError if it isn't a valid time. Arguments: node -- the tree item storing the data zeroBlanks -- replace blank field values with zeros if True """ storedText = node.data.get(self.name, '') if storedText: dateTime = datetime.datetime.strptime(storedText, DateTimeField.isoFormat) return (dateTime - DateTimeField.refDateTime).total_seconds() return 0 if zeroBlanks else None def compareValue(self, node): """Return a value for comparison to other nodes and for sorting. Returns lowercase text for text fields or numbers for non-text fields. DateTime field uses YYYY-MM-DD HH:MM:SS format. Arguments: node -- the tree item storing the data """ return node.data.get(self.name, '') def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Time version converts to HH:MM:SS format. Arguments: value -- the comparison value to adjust """ value = _multipleSpaceRegEx.sub(' ', value.strip()) if not value: return '' if value == _timeStampString: dateTime = datetime.datetime.now() return dateTime.strftime(DateTimeField.isoFormat) try: return self.storedText(value) except ValueError: return value class ChoiceField(HtmlTextField): """Class to handle a field with pre-defined, individual text choices. Stores options and format strings for a choice field type. Provides methods to return formatted data. """ typeName = 'Choice' editSep = '/' defaultFormat = '1/2/3/4' evalHtmlDefault = False fixEvalHtmlSetting = False editorClassName = 'ComboEditor' numChoiceColumns = 1 autoAddChoices = False formatHelpMenuList = [(_('Separator\t/'), '/'), ('', ''), (_('"/" Character\t//'), '//'), ('', ''), (_('Example\t1/2/3/4'), '1/2/3/4')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def setFormat(self, format): """Set the format string and initialize as required. Arguments: format -- the new format string """ super().setFormat(format) self.choiceList = self.splitText(self.format) if self.evalHtml: self.choices = set(self.choiceList) else: self.choices = set([saxutils.escape(choice) for choice in self.choiceList]) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ if storedText not in self.choices: storedText = _errorStr return super().formatOutput(storedText, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if storedText and storedText not in self.choices: raise ValueError if self.evalHtml: return storedText return saxutils.unescape(storedText) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ if not self.evalHtml: editorText = saxutils.escape(editorText) if not editorText or editorText in self.choices: return editorText raise ValueError def comboChoices(self): """Return a list of choices for the combo box. """ return self.choiceList def initDefaultChoices(self): """Return a list of choices for setting the init default. """ return self.choiceList def splitText(self, textStr): """Split textStr using editSep, return a list of strings. Double editSep's are not split (become single). Removes duplicates and empty strings. Arguments: textStr -- the text to split """ result = [] textStr = textStr.replace(self.editSep * 2, '\0') for text in textStr.split(self.editSep): text = text.strip().replace('\0', self.editSep) if text and text not in result: result.append(text) return result class AutoChoiceField(HtmlTextField): """Class to handle a field with automatically populated text choices. Stores options and possible entries for an auto-choice field type. Provides methods to return formatted data. """ typeName = 'AutoChoice' evalHtmlDefault = False fixEvalHtmlSetting = False editorClassName = 'ComboEditor' numChoiceColumns = 1 autoAddChoices = True def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ super().__init__(name, formatData) self.choices = set() def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Arguments: storedText -- the source text to format """ if self.evalHtml: return storedText return saxutils.unescape(storedText) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Arguments: editorText -- the new text entered into the editor """ if self.evalHtml: return editorText return saxutils.escape(editorText) def comboChoices(self): """Return a list of choices for the combo box. """ if self.evalHtml: choices = self.choices else: choices = [saxutils.unescape(text) for text in self.choices] return sorted(choices, key=str.lower) def addChoice(self, text): """Add a new choice. Arguments: text -- the choice to be added """ if text: self.choices.add(text) def clearChoices(self): """Remove all current choices. """ self.choices = set() class CombinationField(ChoiceField): """Class to handle a field with multiple pre-defined text choices. Stores options and format strings for a combination field type. Provides methods to return formatted data. """ typeName = 'Combination' editorClassName = 'CombinationEditor' numChoiceColumns = 2 def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def setFormat(self, format): """Set the format string and initialize as required. Arguments: format -- the new format string """ TextField.setFormat(self, format) if not self.evalHtml: format = saxutils.escape(format) self.choiceList = self.splitText(format) self.choices = set(self.choiceList) self.outputSep = '' def outputText(self, node, oneLine, noHtml, formatHtml, spotRef=None): """Return formatted output text for this field in this node. Sets output separator prior to calling base class methods. Arguments: node -- the tree item storing the data oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix spotRef -- optional, used for ancestor field refs """ self.outputSep = node.formatRef.outputSeparator return super().outputText(node, oneLine, noHtml, formatHtml, spotRef) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ selections, valid = self.sortedSelections(storedText) if valid: result = self.outputSep.join(selections) else: result = _errorStr return TextField.formatOutput(self, result, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ selections = set(self.splitText(storedText)) if selections.issubset(self.choices): if self.evalHtml: return storedText return saxutils.unescape(storedText) raise ValueError def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ if not self.evalHtml: editorText = saxutils.escape(editorText) selections, valid = self.sortedSelections(editorText) if not valid: raise ValueError return self.joinText(selections) def comboChoices(self): """Return a list of choices for the combo box. """ if self.evalHtml: return self.choiceList return [saxutils.unescape(text) for text in self.choiceList] def comboActiveChoices(self, editorText): """Return a sorted list of choices currently in editorText. Arguments: editorText -- the text entered into the editor """ selections, valid = self.sortedSelections(saxutils.escape(editorText)) if self.evalHtml: return selections return [saxutils.unescape(text) for text in selections] def initDefaultChoices(self): """Return a list of choices for setting the init default. """ return [] def sortedSelections(self, inText): """Split inText using editSep and sort like format string. Return a tuple of resulting selection list and bool validity. Valid if all choices are in the format string. Arguments: inText -- the text to split and sequence """ selections = set(self.splitText(inText)) result = [text for text in self.choiceList if text in selections] return (result, len(selections) == len(result)) def joinText(self, textList): """Join the text list using editSep, return the string. Any editSep in text items become double. Arguments: textList -- the list of text items to join """ return self.editSep.join([text.replace(self.editSep, self.editSep * 2) for text in textList]) class AutoCombinationField(CombinationField): """Class for a field with multiple automatically populated text choices. Stores options and possible entries for an auto-choice field type. Provides methods to return formatted data. """ typeName = 'AutoCombination' autoAddChoices = True defaultFormat = '' formatHelpMenuList = [] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ super().__init__(name, formatData) self.choices = set() self.outputSep = '' def outputText(self, node, oneLine, noHtml, formatHtml, spotRef=None): """Return formatted output text for this field in this node. Sets output separator prior to calling base class methods. Arguments: node -- the tree item storing the data oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix spotRef -- optional, used for ancestor field refs """ self.outputSep = node.formatRef.outputSeparator return super().outputText(node, oneLine, noHtml, formatHtml, spotRef) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ result = self.outputSep.join(self.splitText(storedText)) return TextField.formatOutput(self, result, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Arguments: storedText -- the source text to format """ if self.evalHtml: return storedText return saxutils.unescape(storedText) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Also resets outputSep, to be defined at the next output. Arguments: editorText -- the new text entered into the editor """ self.outputSep = '' if not self.evalHtml: editorText = saxutils.escape(editorText) selections = sorted(self.splitText(editorText), key=str.lower) return self.joinText(selections) def comboChoices(self): """Return a list of choices for the combo box. """ if self.evalHtml: choices = self.choices else: choices = [saxutils.unescape(text) for text in self.choices] return sorted(choices, key=str.lower) def comboActiveChoices(self, editorText): """Return a sorted list of choices currently in editorText. Arguments: editorText -- the text entered into the editor """ selections, valid = self.sortedSelections(saxutils.escape(editorText)) if self.evalHtml: return selections return [saxutils.unescape(text) for text in selections] def sortedSelections(self, inText): """Split inText using editSep and sort like format string. Return a tuple of resulting selection list and bool validity. This version always returns valid. Arguments: inText -- the text to split and sequence """ selections = sorted(self.splitText(inText), key=str.lower) return (selections, True) def addChoice(self, text): """Add a new choice. Arguments: text -- the stored text combinations to be added """ for choice in self.splitText(text): self.choices.add(choice) def clearChoices(self): """Remove all current choices. """ self.choices = set() class BooleanField(ChoiceField): """Class to handle a general boolean field format type. Stores options and format strings for a boolean field type. Provides methods to return formatted data. """ typeName = 'Boolean' defaultFormat = _('yes/no') evalHtmlDefault = False fixEvalHtmlSetting = False sortTypeStr ='30_bool' formatHelpMenuList = [(_('true/false'), 'true/false'), (_('T/F'), 'T/F'), ('', ''), (_('yes/no'), 'yes/no'), (_('Y/N'), 'Y/N'), ('', ''), ('1/0', '1/0')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def setFormat(self, format): """Set the format string and initialize as required. Arguments: format -- the new format string """ HtmlTextField.setFormat(self, format) self.strippedFormat = removeMarkup(self.format) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ try: text = genboolean.GenBoolean(storedText).boolStr(self.format) except ValueError: text = _errorStr if not self.evalHtml: text = saxutils.escape(text) return HtmlTextField.formatOutput(self, text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' boolFormat = self.strippedFormat if self.evalHtml else self.format return genboolean.GenBoolean(storedText).boolStr(boolFormat) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ if not editorText: return '' boolFormat = self.strippedFormat if self.evalHtml else self.format try: return repr(genboolean.GenBoolean().setFromStr(editorText, boolFormat)) except ValueError: return repr(genboolean.GenBoolean(editorText)) def comboChoices(self): """Return a list of choices for the combo box. """ if self.evalHtml: return self.splitText(self.strippedFormat) return self.splitText(self.format) def initDefaultChoices(self): """Return a list of choices for setting the init default. """ return self.comboChoices() def mathValue(self, node, zeroBlanks=True, noMarkup=True): """Return a value to be used in math field equations. Return None if blank and not zeroBlanks, raise a ValueError if it isn't a valid boolean. Arguments: node -- the tree item storing the data zeroBlanks -- replace blank field values with zeros if True """ storedText = node.data.get(self.name, '') if storedText: return genboolean.GenBoolean(storedText).value return False if zeroBlanks else None def compareValue(self, node): """Return a value for comparison to other nodes and for sorting. Returns lowercase text for text fields or numbers for non-text fields. Bool fields return True or False values. Arguments: node -- the tree item storing the data """ storedText = node.data.get(self.name, '') try: return genboolean.GenBoolean(storedText).value except ValueError: return False def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Bool version converts to a bool value. Arguments: value -- the comparison value to adjust """ try: return genboolean.GenBoolean().setFromStr(value, self.format).value except ValueError: try: return genboolean.GenBoolean(value).value except ValueError: return False class ExternalLinkField(HtmlTextField): """Class to handle a field containing various types of external HTML links. Protocol choices include http, https, file, mailto. Stores data as HTML tags, shows in editors as "protocol:address [name]". """ typeName = 'ExternalLink' evalHtmlDefault = False editorClassName = 'ExtLinkEditor' sortTypeStr ='60_link' def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ super().__init__(name, formatData) def addressAndName(self, storedText): """Return the link title and the name from the given stored link. Raise ValueError if the stored text is not formatted as a link. Arguments: storedText -- the source text to format """ if not storedText: return ('', '') linkMatch = linkRegExp.search(storedText) if not linkMatch: raise ValueError address, name = linkMatch.groups() return (address, name) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ if noHtml: linkMatch = linkRegExp.search(storedText) if linkMatch: address, name = linkMatch.groups() storedText = name.strip() if not storedText: storedText = address.lstrip('#') return super().formatOutput(storedText, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' address, name = self.addressAndName(storedText) name = name.strip() if not name: name = urltools.shortName(address) return '{0} [{1}]'.format(address, name) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ if not editorText: return '' nameMatch = linkSeparateNameRegExp.match(editorText) if nameMatch: address, name = nameMatch.groups() else: raise ValueError return '{1}'.format(address.strip(), name.strip()) def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Link fields use link address. Arguments: value -- the comparison value to adjust """ if not value: return '' try: address, name = self.addressAndName(value) except ValueError: return value.lower() return address.lstrip('#').lower() class InternalLinkField(ExternalLinkField): """Class to handle a field containing internal links to nodes. Stores data as HTML local link tag, shows in editors as "id [name]". """ typeName = 'InternalLink' editorClassName = 'IntLinkEditor' supportsInitDefault = False def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ super().__init__(name, formatData) def editorText(self, node): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Also raises a ValueError if the link is not a valid destination, with the editor text as the second argument to the exception. Arguments: node -- the tree item storing the data """ storedText = node.data.get(self.name, '') return self.formatEditorText(storedText, node.treeStructureRef()) def formatEditorText(self, storedText, treeStructRef): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Also raises a ValueError if the link is not a valid destination, with the editor text as the second argument to the exception. Arguments: storedText -- the source text to format treeStructRef -- ref to the tree structure to get the linked title """ if not storedText: return '' address, name = self.addressAndName(storedText) address = address.lstrip('#') targetNode = treeStructRef.nodeDict.get(address, None) linkTitle = targetNode.title() if targetNode else _errorStr name = name.strip() if not name and targetNode: name = linkTitle result = 'LinkTo: {0} [{1}]'.format(linkTitle, name) if linkTitle == _errorStr: raise ValueError('invalid address', result) return result def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Uses the "address [name]" format as input, not the final editor form. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new editor text in "address [name]" format """ if not editorText: return '' nameMatch = linkSeparateNameRegExp.match(editorText) if not nameMatch: raise ValueError address, name = nameMatch.groups() if not address: raise ValueError('invalid address', '') if not name: name = _errorStr result = '{1}'.format(address.strip(), name.strip()) if name == _errorStr: raise ValueError('invalid name', result) return result class PictureField(HtmlTextField): """Class to handle a field containing various types of external HTML links. Protocol choices include http, https, file, mailto. Stores data as HTML tags, shows in editors as "protocol:address [name]". """ typeName = 'Picture' evalHtmlDefault = False editorClassName = 'PictureLinkEditor' sortTypeStr ='60_link' def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the attributes that define this field's format """ super().__init__(name, formatData) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ if noHtml: linkMatch = _imageRegExp.search(storedText) if linkMatch: address = linkMatch.group(1) storedText = address.strip() return super().formatOutput(storedText, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not storedText: return '' linkMatch = _imageRegExp.search(storedText) if not linkMatch: raise ValueError return linkMatch.group(1) def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ editorText = editorText.strip() if not editorText: return '' nameMatch = linkSeparateNameRegExp.match(editorText) if nameMatch: address, name = nameMatch.groups() else: address = editorText name = urltools.shortName(address) return ''.format(editorText) def adjustedCompareValue(self, value): """Return value adjusted like the compareValue for use in conditionals. Link fields use link address. Arguments: value -- the comparison value to adjust """ if not value: return '' linkMatch = _imageRegExp.search(value) if not linkMatch: return value.lower() return linkMatch.group(1).lower() class RegularExpressionField(HtmlTextField): """Class to handle a field format type controlled by a regular expression. Stores options and format strings for a number field type. Provides methods to return formatted data. """ typeName = 'RegularExpression' defaultFormat = '.*' evalHtmlDefault = False fixEvalHtmlSetting = False editorClassName = 'LineEditor' formatHelpMenuList = [(_('Any Character\t.'), '.'), (_('End of Text\t$'), '$'), ('', ''), (_('0 Or More Repetitions\t*'), '*'), (_('1 Or More Repetitions\t+'), '+'), (_('0 Or 1 Repetitions\t?'), '?'), ('', ''), (_('Set of Numbers\t[0-9]'), '[0-9]'), (_('Lower Case Letters\t[a-z]'), '[a-z]'), (_('Upper Case Letters\t[A-Z]'), '[A-Z]'), (_('Not a Number\t[^0-9]'), '[^0-9]'), ('', ''), (_('Or\t|'), '|'), (_('Escape a Special Character\t\\'), '\\')] def __init__(self, name, formatData=None): """Initialize a field format type. Arguments: name -- the field name string formatData -- the dict that defines this field's format """ super().__init__(name, formatData) def setFormat(self, format): """Set the format string and initialize as required. Raise a ValueError if the format is illegal. Arguments: format -- the new format string """ try: re.compile(format) except re.error: raise ValueError super().setFormat(format) def formatOutput(self, storedText, oneLine, noHtml, formatHtml): """Return formatted output text from stored text for this field. Arguments: storedText -- the source text to format oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix """ match = re.fullmatch(self.format, saxutils.unescape(storedText)) if not storedText or match: text = storedText else: text = _errorStr return super().formatOutput(text, oneLine, noHtml, formatHtml) def formatEditorText(self, storedText): """Return text formatted for use in the data editor. Raises a ValueError if the data does not match the format. Arguments: storedText -- the source text to format """ if not self.evalHtml: storedText = saxutils.unescape(storedText) match = re.fullmatch(self.format, storedText) if not storedText or match: return storedText raise ValueError def storedText(self, editorText): """Return new text to be stored based on text from the data editor. Raises a ValueError if the data does not match the format. Arguments: editorText -- the new text entered into the editor """ match = re.fullmatch(self.format, editorText) if not editorText or match: if self.evalHtml: return editorText return saxutils.escape(editorText) raise ValueError class AncestorLevelField(TextField): """Placeholder format for ref. to ancestor fields at specific levels. """ typeName = 'AncestorLevel' def __init__(self, name, ancestorLevel=1): """Initialize a field format placeholder type. Arguments: name -- the field name string ancestorLevel -- the number of generations to go back """ super().__init__(name, {}) self.ancestorLevel = ancestorLevel def outputText(self, node, oneLine, noHtml, formatHtml, spotRef=None): """Return formatted output text for this field in this node. Finds the appropriate ancestor node to get the field text. Arguments: node -- the tree node to start from oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix spotRef -- optional, used for ancestor field refs """ if not spotRef: spotRef = node.spotByNumber(0) for num in range(self.ancestorLevel): spotRef = spotRef.parentSpot if not spotRef: return '' try: field = spotRef.nodeRef.formatRef.fieldDict[self.name] except (AttributeError, KeyError): return '' return field.outputText(spotRef.nodeRef, oneLine, noHtml, formatHtml, spotRef) def sepName(self): """Return the name enclosed with {* *} separators """ return '{{*{0}{1}*}}'.format(self.ancestorLevel * '*', self.name) class AnyAncestorField(TextField): """Placeholder format for ref. to matching ancestor fields at any level. """ typeName = 'AnyAncestor' def __init__(self, name): """Initialize a field format placeholder type. Arguments: name -- the field name string """ super().__init__(name, {}) def outputText(self, node, oneLine, noHtml, formatHtml, spotRef=None): """Return formatted output text for this field in this node. Finds the appropriate ancestor node to get the field text. Arguments: node -- the tree node to start from oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix spotRef -- optional, used for ancestor field refs """ if not spotRef: spotRef = node.spotByNumber(0) while spotRef.parentSpot: spotRef = spotRef.parentSpot try: field = spotRef.nodeRef.formatRef.fieldDict[self.name] except (AttributeError, KeyError): pass else: return field.outputText(spotRef.nodeRef, oneLine, noHtml, formatHtml, spotRef) return '' def sepName(self): """Return the name enclosed with {* *} separators """ return '{{*?{0}*}}'.format(self.name) class ChildListField(TextField): """Placeholder format for ref. to matching ancestor fields at any level. """ typeName = 'ChildList' def __init__(self, name): """Initialize a field format placeholder type. Arguments: name -- the field name string """ super().__init__(name, {}) def outputText(self, node, oneLine, noHtml, formatHtml, spotRef=None): """Return formatted output text for this field in this node. Returns a joined list of matching child field data. Arguments: node -- the tree node to start from oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix spotRef -- optional, used for ancestor field refs """ result = [] for child in node.childList: try: field = child.formatRef.fieldDict[self.name] except KeyError: pass else: result.append(field.outputText(child, oneLine, noHtml, formatHtml, spotRef)) outputSep = node.formatRef.outputSeparator return outputSep.join(result) def sepName(self): """Return the name enclosed with {* *} separators """ return '{{*&{0}*}}'.format(self.name) class DescendantCountField(TextField): """Placeholder format for count of descendants at a given level. """ typeName = 'DescendantCount' def __init__(self, name, descendantLevel=1): """Initialize a field format placeholder type. Arguments: name -- the field name string descendantLevel -- the level to descend to """ super().__init__(name, {}) self.descendantLevel = descendantLevel def outputText(self, node, oneLine, noHtml, formatHtml, spotRef=None): """Return formatted output text for this field in this node. Returns a count of descendants at the approriate level. Arguments: node -- the tree node to start from oneLine -- if True, returns only first line of output (for titles) noHtml -- if True, removes all HTML markup (for titles, etc.) formatHtml -- if False, escapes HTML from prefix & suffix spotRef -- optional, used for ancestor field refs """ newNodes = [node] for i in range(self.descendantLevel): prevNodes = newNodes newNodes = [] for child in prevNodes: newNodes.extend(child.childList) return repr(len(newNodes)) def sepName(self): """Return the name enclosed with {* *} separators """ return '{{*#{0}*}}'.format(self.name) #### Utility Functions #### def removeMarkup(text): """Return text with all HTML Markup removed and entities unescaped. Any
    tags are replaced with newlines. """ text = _lineBreakRegEx.sub('\n', text) text = _stripTagRe.sub('', text) return saxutils.unescape(text) def adjOutDateFormat(dateFormat): """Replace Linux lead zero removal with Windows version in date formats. Arguments: dateFormat -- the format to modify """ if sys.platform.startswith('win'): dateFormat = dateFormat.replace('%-', '%#') return dateFormat def adjInDateFormat(dateFormat): """Remove lead zero formatting in date formats for reading dates. Arguments: dateFormat -- the format to modify """ return dateFormat.replace('%-', '%') def adjTimeAmPm(timeFormat, time): """Add AM/PM to timeFormat if in format and locale skips it. Arguments: timeFormat -- the format to modify time -- the datetime object to check for AM/PM """ if '%p' in timeFormat and time.strftime('%I (%p)').endswith('()'): amPm = 'AM' if time.hour < 12 else 'PM' timeFormat = re.sub(r'(?/. """ def __init__(self, boolStr='true'): """Initialize a GenBoolean object with any format from _formatDict. Raises ValueError with an inappropriate argument. Arguments: boolStr -- the string to evaluate """ self.setBool(boolStr) def setBool(self, boolStr): """Initialize a GenBoolean object with any format from _formatDict. Raises ValueError with an inappropriate argument. Arguments: boolStr -- the string to evaluate """ try: self.value = _formatDict[boolStr.lower()] except KeyError: raise ValueError def setFromStr(self, boolStr, strFormat='yes/no'): """Set boolean value based on given format string. Raises ValueError with an inappropriate argument. Returns self. Arguments: boolStr -- the string to evaluate strFormat -- a text format in True/False style """ try: self.value = self.customFormatDict(strFormat)[boolStr.lower()] except KeyError: raise ValueError return self @staticmethod def customFormatDict(strFormat): """Return a dictionary based on the format. The dictionary includes conversions in both directions. String keys are in lower case. Double editSep's are not split (become single). Raises ValueError with an inappropriate format. Arguments: strFormat -- a text format in True/False style """ strFormat = strFormat.replace('//', '\0') trueVal, falseVal = strFormat.split('/', 1) trueVal = trueVal.replace('\0', '/') falseVal = falseVal.replace('\0', '/') if not trueVal or not falseVal or trueVal == falseVal: raise ValueError return {trueVal.lower():True, falseVal.lower():False, True:trueVal, False:falseVal} def boolStr(self, strFormat='yes/no'): """Return the boolean string in the given strFormat. Arguments: Format: strFormat -- a text format in True/False style """ return self.customFormatDict(strFormat)[self.value] def clone(self): """Return cloned instance. """ return self.__class__(self.value) def __repr__(self): """Outputs in general string fomat. """ return repr(self.value) def __eq__(self, other): """Equality test. """ try: return self.value == other.value except AttributeError: return self.value == other def __ne__(self, other): """Non-equality test. """ try: return self.value != other.value except AttributeError: return self.value != other def __hash__(self): """Allow use as dictionary key. """ return hash(self.value) def __nonzero(self): """Allow truth testing. """ return self.value TreeLine-3.2.1/source/gennumber.py000066400000000000000000000246711506556630100171010ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # gennumber.py, provides a class for number formating # # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import math class GenNumber: """Class to store & format number values. Uses a simple syntax (sequence of '#', '0', etc.) for formatting. """ def __init__(self, num=0): """Initialize a GenNumber object with a number, string or a GenNumber. Raises ValueError with an inappropriate argument. Accepts one of the following arguments as num to initialize: 1. int value 2. float value 3. string in common int or float format 4. GenNumber instance """ self.setNumber(num) def setNumber(self, num): """Sets the number value from an int, float, string or a GenNumber. Raises ValueError with an inappropriate argument. Arguments: num -- the value in int, float, string or GenNumber format """ try: self.num = int(str(num)) except ValueError: self.num = float(str(num)) def setFromStr(self, numStr, strFormat=r'#\,###'): """Set number value based on given format string. Removes the extra characters from format and uses format's radix char. Returns self. Arguments: numStr -- the string to evaluate strFormat -- the format to use to interpret the number string """ radix = _getRadix(strFormat) strFormat = _unescapeFormat(radix, strFormat).strip() extraChar = re.sub(r'[#0\seE\-\+{}]'.format(re.escape(radix)), '', strFormat) if extraChar: numStr = re.sub('[{}]'.format(re.escape(extraChar)), '', numStr) if radix == ',': numStr = numStr.replace(',', '.') self.setNumber(numStr) return self def numStr(self, strFormat='#.##'): """Return the number string in the given format, including exponents. Format: # = optional digit 0 = required digit e = exponent - = optional sign + = required sign space (external) = digit or space space (internal) = thousands sep \\, = thousands separator \\. = thousands separator Arguments: strFormat -- format for number export """ formMain, formExp = _doubleSplit('eE', strFormat) if not formExp: return self.basicNumStr(strFormat) exp = math.floor(math.log10(abs(self.num))) num = self.num / 10**exp totPlcs = len(re.findall(r'[#0]', formMain)) num = round(num, totPlcs - 1 if totPlcs > 0 else 0) radix = _getRadix(strFormat) wholePlcs = len(re.findall(r'[#0]', _doubleSplit(radix, formMain)[0])) expChg = wholePlcs - int(math.floor(math.log10(abs(num)))) - 1 num = num * 10**expChg exp -= expChg c = 'e' if 'e' in strFormat else 'E' return '{0}{1}{2}'.format(GenNumber(num).basicNumStr(formMain), c, GenNumber(exp).basicNumStr(formExp)) def basicNumStr(self, strFormat='#.##'): """Return number string in the given format, without exponent support. Format: # = optional digit 0 = required digit - = optional sign + = required sign space (external) = digit or space space (internal) = thousands sep \\, = thousands separator \\. = thousands separator Arguments: strFormat -- format for number export """ radix = _getRadix(strFormat) strFormat = _unescapeFormat(radix, strFormat) formWhole, formFract = _doubleSplit(radix, strFormat) decPlcs = len(re.findall(r'[#0]', formFract)) numWhole, numFract = _doubleSplit('.', '{0:.{1}f}'.format(self.num, decPlcs)) numFract = numFract.rstrip('0') numWhole, numFract = list(numWhole), list(numFract) formWhole, formFract = list(formWhole), list(formFract) sign = '+' if numWhole[0] == '-': sign = numWhole.pop(0) result = [] while numWhole or formWhole: c = formWhole.pop() if formWhole else '' if c and c not in '#0 +-': if numWhole or '0' in formWhole: result.insert(0, c) elif numWhole and c != ' ': result.insert(0, numWhole.pop()) if c and c in '+-': formWhole.append(c) elif c in '0 ': result.insert(0, c) elif c in '+-': if sign == '-' or c == '+': result.insert(0, sign) sign = '' if sign == '-': if result[0] == ' ': result = [re.sub(r'\s(?!\s)', '-', ''.join(result), 1)] else: result.insert(0, '-') if formFract or (strFormat and strFormat[-1] == radix): result.append(radix) while formFract: c = formFract.pop(0) if c not in '#0 ': if numFract or '0' in formFract: result.append(c) elif numFract: result.append(numFract.pop(0)) elif c in '0 ': result.append('0') return ''.join(result) def clone(self): """Return cloned instance. """ return self.__class__(self.num) def __repr__(self): """Outputs in general string fomat. """ return repr(self.num) def __eq__(self, other): """Equality test. """ try: return self.num == other.num except AttributeError: return self.num == other def __ne__(self, other): """Non-equality test. """ try: return self.num != other.num except AttributeError: return self.num != other def __lt__(self, other): """Less than test. """ try: return self.num < other.num except AttributeError: return self.num < other def __gt__(self, other): """Greater than test. """ try: return self.num > other.num except AttributeError: return self.num > other def __le__(self, other): """Less than or equal to test. """ try: return self.num <= other.num except AttributeError: return self.num <= other def __ge__(self, other): """Greater than or equal to test. """ try: return self.num >= other.num except AttributeError: return self.num >= other def __add__(self, other): """Addition operator. """ try: return self.num + other.num except AttributeError: return self.num + other def __radd__(self, other): """Reverse addition operator. """ return other + self.num def __sub__(self, other): """Subtraction operator. """ try: return self.num - other.num except AttributeError: return self.num - other def __rsub__(self, other): """Reverse subtraction operator. """ return other - self.num def __mul__(self, other): """Multiplication operator. """ try: return self.num * other.num except AttributeError: return self.num * other def __rmul__(self, other): """Reverse multiplication operator. """ return other * self.num def __truediv__(self, other): """True division operator. """ try: return self.num / other.num except AttributeError: return self.num / other def __rtruediv__(self, other): """Reverse true division operator. """ return other / self.num def __floordiv__(self, other): """Floor division operator. """ try: return self.num // other.num except AttributeError: return self.num // other def __rfloordiv__(self, other): """Reverse floor division operator. """ return other // self.num def __int__(self): """Return integer value. """ return int(self.num) def __float__(self): """Return float value. """ return float(self.num) def __round__(self): """Return rounded value. """ return round(self.num) def __hash__(self): """Allow use as dictionary key. """ return hash(self.num) ######### Utility Functions ########## def _doubleSplit(sepChars, string): """Return tuple of string split in two, separated by one of sepChars. Returns a tuple, size 2, with the second entry empty if no sep found. Arguments: sepChars -- a string of separator characters string -- the string to split """ for sep in sepChars: result = string.split(sep, 1) if len(result) == 2: return result return (string, '') def _getRadix(strFormat): """Return the radix character (. or ,) used in format. Infers from use of slashed separators and non-slashed radix. Assumes radix is "." if ambiguous. Arguments: strFormat -- the string format to evaluate """ if not r'\,' in strFormat and (r'\.' in strFormat or (',' in strFormat and not '.' in strFormat)): return ',' return '.' def _unescapeFormat(radix, strFormat): """Return format with escapes removed from non-radix separators. Arguments: radix -- the current radix character strFormat - the string format to modify """ if radix == '.': return strFormat.replace(r'\,', ',') return strFormat.replace(r'\.', '.') TreeLine-3.2.1/source/globalref.py000066400000000000000000000035531506556630100170500ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # globalref.py, provides a module for access to a few global variables # # TreeLine, an information storage program # Copyright (C) 2017, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** mainControl = None genOptions = None miscOptions = None histOptions = None toolbarOptions = None keyboardOptions = None toolIcons = None treeIcons = None localTextEncoding = '' lang = '' fileFilters = {'trlnopen': '{} (*.trln *.trln.gz *.trl)'. format(_('All TreeLine Files')), 'trlnv3': '{} (*.trln *.trln.gz)'.format(_('TreeLine Files')), 'trlnsave': '{} (*.trln)'.format(_('TreeLine Files')), 'trlngz': '{} (*.trln *.trln.gz)'. format(_('TreeLine Files - Compressed')), 'trlnenc': '{} (*.trln)'. format(_('TreeLine Files - Encrypted')), 'trl': '{} (*.trl *.xml)'.format(_('Old TreeLine Files')), 'all': '{} (*)'.format(_('All Files')), 'html': '{} (*.html *.htm)'.format(_('HTML Files')), 'txt': '{} (*.txt)'.format(_('Text Files')), 'xml': '{} (*.xml)'.format(_('XML Files')), 'csv': '{} (*.csv)'.format(_('CSV (Comma Delimited) Files')), 'odt': '{} (*.odt)'.format(_('ODF Text Files')), 'hjt': '{} (*.hjt)'.format(_('Treepad Files')), 'pdf': '{} (*.pdf)'.format(_('PDF Files'))} TreeLine-3.2.1/source/helpview.py000066400000000000000000000126051506556630100167340ustar00rootroot00000000000000#!/usr/bin/env python3 #**************************************************************************** # helpview.py, provides a window for viewing an html help file # # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #***************************************************************************** from PyQt6.QtCore import QUrl, Qt from PyQt6.QtGui import (QAction, QTextDocument) from PyQt6.QtWidgets import (QLabel, QLineEdit, QMainWindow, QMenu, QStatusBar, QTextBrowser) import dataeditors class HelpView(QMainWindow): """Main window for viewing an html help file. """ def __init__(self, pathObj, caption, icons, parent=None): """Helpview initialize with text. Arguments: pathObj -- a path object for the help file caption -- the window caption icons -- dict of view icons """ QMainWindow.__init__(self, parent) self.setAttribute(Qt.WidgetAttribute.WA_QuitOnClose, False) self.setWindowFlags(Qt.WindowType.Window) self.setStatusBar(QStatusBar()) self.textView = HelpViewer(self) self.setCentralWidget(self.textView) self.textView.setSearchPaths([str(pathObj.parent)]) self.textView.setSource(QUrl(pathObj.as_uri())) self.resize(520, 440) self.setWindowTitle(caption) tools = self.addToolBar(_('Tools')) self.menu = QMenu(self.textView) self.textView.highlighted.connect(self.showLink) backAct = QAction(_('&Back'), self) backAct.setIcon(icons['helpback']) tools.addAction(backAct) self.menu.addAction(backAct) backAct.triggered.connect(self.textView.backward) backAct.setEnabled(False) self.textView.backwardAvailable.connect(backAct.setEnabled) forwardAct = QAction(_('&Forward'), self) forwardAct.setIcon(icons['helpforward']) tools.addAction(forwardAct) self.menu.addAction(forwardAct) forwardAct.triggered.connect(self.textView.forward) forwardAct.setEnabled(False) self.textView.forwardAvailable.connect(forwardAct.setEnabled) homeAct = QAction(_('&Home'), self) homeAct.setIcon(icons['helphome']) tools.addAction(homeAct) self.menu.addAction(homeAct) homeAct.triggered.connect(self.textView.home) tools.addSeparator() tools.addSeparator() findLabel = QLabel(_(' Find: '), self) tools.addWidget(findLabel) self.findEdit = QLineEdit(self) tools.addWidget(self.findEdit) self.findEdit.textEdited.connect(self.findTextChanged) self.findEdit.returnPressed.connect(self.findNext) self.findPreviousAct = QAction(_('Find &Previous'), self) self.findPreviousAct.setIcon(icons['helpprevious']) tools.addAction(self.findPreviousAct) self.menu.addAction(self.findPreviousAct) self.findPreviousAct.triggered.connect(self.findPrevious) self.findPreviousAct.setEnabled(False) self.findNextAct = QAction(_('Find &Next'), self) self.findNextAct.setIcon(icons['helpnext']) tools.addAction(self.findNextAct) self.menu.addAction(self.findNextAct) self.findNextAct.triggered.connect(self.findNext) self.findNextAct.setEnabled(False) def showLink(self, url): """Send link text to the statusbar. Arguments: url -- the QUrl link to show """ self.statusBar().showMessage(url.toString()) def findTextChanged(self, text): """Update find controls based on text in text edit. Arguments: text -- the search text """ self.findPreviousAct.setEnabled(len(text) > 0) self.findNextAct.setEnabled(len(text) > 0) def findPrevious(self): """Command to find the previous string. """ if self.textView.find(self.findEdit.text(), QTextDocument.FindFlag.FindBackward): self.statusBar().clearMessage() else: self.statusBar().showMessage(_('Text string not found')) def findNext(self): """Command to find the next string. """ if self.textView.find(self.findEdit.text()): self.statusBar().clearMessage() else: self.statusBar().showMessage(_('Text string not found')) class HelpViewer(QTextBrowser): """Shows an html help file. """ def __init__(self, parent=None): """Initialize the viewer. Arguments: parent -- the parent widget, if given """ QTextBrowser.__init__(self, parent) def doSetSource(self, url, resType): """Called when user clicks on a URL. Arguments: url -- the clicked on QUrl """ name = url.toString() if name.startswith('http'): dataeditors.openExtUrl(name) else: super().doSetSource(url, resType) def contextMenuEvent(self, event): """Init popup menu on right click"". Arguments: event -- the menu event """ self.parentWidget().menu.exec(event.globalPos()) TreeLine-3.2.1/source/icondict.py000066400000000000000000000104621506556630100167040ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # icondict.py, provides a class to load and store icons # # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** from PyQt6.QtGui import QIcon, QPixmap _iconExtension = ('.png', '.bmp', '.ico', '.gif') defaultName = 'default' noneName = 'NoIcon' class IconDict(dict): """Loads and stores icons by name. """ def __init__(self, pathObjList, subPaths=None): """Set icon paths and initialize variables. The first potential path that has icons is used. Arguments: pathObjList -- a list of path objects to check for icons subPaths -- a list of optional subpaths under the base paths """ super().__init__() self.pathObjList = [] self.subPaths = [''] self.addIconPath(pathObjList, subPaths) self.allLoaded = False self[noneName] = None def addIconPath(self, pathObjList, subPaths=None): """Add an icon path and set the subPaths if given. Arguments: pathObjList -- a list of path objects to check for icons subPaths -- a list of optional subpaths under the base paths """ if subPaths: self.subPaths = subPaths for mainPath in pathObjList: for subPath in self.subPaths: dirPath = mainPath / subPath try: for fullPath in dirPath.iterdir(): pixmap = QPixmap(str(fullPath)) if not pixmap.isNull(): if mainPath not in self.pathObjList: self.pathObjList.append(mainPath) break except OSError: pass def getIcon(self, name, substitute=False): """Return an icon matching the name. Load the icon if it isn't already loaded. If not found, return None or substitute a default icon. Arguments: name -- the name of the icon to retrieve substitute -- if True, return a default icon if not found """ try: icon = self[name] except KeyError: icon = self.loadIcon(name) if not icon and substitute: icon = self.getIcon(defaultName) return icon def loadIcon(self, name): """Load an icon from the icon path, add to dict and return the icon. Return None if not found. Arguments: name -- the name of the icon to load """ icon = QIcon() for path in self.pathObjList: for ext in _iconExtension: fileName = name + ext for subPath in self.subPaths: pixmap = QPixmap(str(path.joinpath(subPath, fileName))) if not pixmap.isNull(): icon.addPixmap(pixmap) if not icon.isNull(): self[name] = icon return icon return None def loadIcons(self, nameList): """Load icons based on a name list. Arguments: nameList -- the list of names to load """ for name in nameList: self.loadIcon(name) def loadAllIcons(self): """Load all of the icons available on path list. """ self.clear() self[noneName] = None for mainPath in self.pathObjList: for subPath in self.subPaths: dirPath = mainPath / subPath try: for fullPath in dirPath.iterdir(): pixmap = QPixmap(str(fullPath)) if not pixmap.isNull(): name = fullPath.stem icon = self.setdefault(name, QIcon()) icon.addPixmap(pixmap) except OSError: pass self.allLoaded = True TreeLine-3.2.1/source/imports.py000066400000000000000000001263631506556630100166150ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # imports.py, provides classes for a file import dialog and import functions # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import pathlib import re import collections import zipfile import csv import html.parser import xml.sax.saxutils from xml.etree import ElementTree from PyQt6.QtCore import Qt from PyQt6.QtWidgets import QApplication, QDialog, QFileDialog, QMessageBox import miscdialogs import treenode import treestructure import treemodel import nodeformat import treeformats import urltools import globalref methods = collections.OrderedDict() methods.update([(_('Text'), None), (_('&Tab indented text, one node per line'), 'importTabbedText'), (_('Co&mma delimited (CSV) text table with level column && ' 'header row'), 'importTableCsvLevels'), (_('Comma delimited (CSV) text table &with header row'), 'importTableCsv'), (_('Tab delimited text table with header &row'), 'importTableTabbed'), (_('Plain text, one &node per line (CR delimited)'), 'importTextLines'), (_('Plain text ¶graphs (blank line delimited)'), 'importTextPara'), (_('Bookmarks'), None), (_('&HTML bookmarks (Mozilla Format)'), 'importMozilla'), (_('&XML bookmarks (XBEL format)'), 'importXbel'), (_('Other'), None), (_('Old Tree&Line File (1.x or 2.x)'), 'importOldTreeLine'), (_('Treepad &file (text nodes only)'), 'importTreePad'), (_('&Generic XML (non-TreeLine file)'), 'importXml'), (_('Open &Document (ODF) outline'), 'importOdfText')]) fileFilters = {'importTabbedText': 'txt', 'importTableCsvLevels': 'csv', 'importTableCsv': 'csv', 'importTableTabbed': 'txt', 'importTextLines': 'txt', 'importTextPara': 'txt', 'importMozilla': 'html', 'importXbel': 'xml', 'importOldTreeLine': 'trl', 'importTreePad': 'hjt', 'importXml': 'xml', 'importOdfText': 'odt'} oldDateTimeConv = {'d': '%-d', 'dd': '%d', 'ddd': '%a', 'dddd': '%A', 'M': '%-m', 'MM': '%m', 'MMM': '%b', 'MMMM': '%B', 'yy': '%y', 'yyyy': '%Y', 'H': '%-H', 'HH': '%H', 'h': '%-I', 'hh': '%I', 'm': '%-M', 'mm': '%M', 's': '%-S', 'ss': '%S', 'zzz': '%f', 'AP': '%p', 'ap': '%p'} bookmarkFolderTypeName = _('FOLDER') bookmarkLinkTypeName = _('BOOKMARK') bookmarkSeparatorTypeName = _('SEPARATOR') bookmarkLinkFieldName = _('Link') textFieldName = _('Text') genericXmlTextFieldName = 'Element_Data' htmlUnescapeDict = {'amp': '&', 'lt': '<', 'gt': '>', 'quot': '"'} class ImportControl: """Control file imports of alt file types. """ def __init__(self, pathObj=None): """Initialize the import control object. Arguments: pathObj -- the path object to import if given, o/w prompt user """ self.pathObj = pathObj self.errorMessage = '' # below members for old TreeLine file imports self.treeLineImportVersion = [] self.treeLineRootAttrib = {} self.treeLineOldFieldAttr = {} def interactiveImport(self, addWarning=False): """Prompt the user for import type & proceed with import. Return the structure if import is successful, otherwise None Arguments: addWarning - if True, add non-valid file warning to dialog """ dialog = miscdialogs.RadioChoiceDialog(_('Import File'), _('Choose Import Method'), methods.items(), QApplication. activeWindow()) if addWarning: fileName = self.pathObj.name dialog.addLabelBox(_('Invalid File'), _('"{0}" is not a valid TreeLine file.\n\n' 'Use an import filter?').format(fileName)) if dialog.exec() != QDialog.DialogCode.Accepted: return None method = dialog.selectedButton() if not self.pathObj: filters = ';;'.join((globalref.fileFilters[fileFilters[method]], globalref.fileFilters['all'])) defaultFilePath = str(globalref.mainControl.defaultPathObj(True)) filePath, selFltr = QFileDialog.getOpenFileName(QApplication. activeWindow(), _('TreeLine - Import File'), defaultFilePath, filters) if not filePath: return None self.pathObj = pathlib.Path(filePath) self.errorMessage = '' try: QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) structure = getattr(self, method)() QApplication.restoreOverrideCursor() except IOError: QApplication.restoreOverrideCursor() QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - could not read file {0}'). format(self.pathObj)) return None except UnicodeDecodeError: prevEncoding = globalref.localTextEncoding globalref.localTextEncoding = 'utf-8' structure = getattr(self, method)() globalref.localTextEncoding = prevEncoding QApplication.restoreOverrideCursor() if not structure: message = _('Error - improper format in {0}').format(self.pathObj) if self.errorMessage: message = '{0}\n{1}'.format(message, self.errorMessage) self.errorMessage = '' QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', message) return structure def importTabbedText(self): """Import a file with tabbed title structure. Return the structure if import is successful, otherwise None """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) formatRef = structure.childList[0].formatRef structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] nodeList = [] with self.pathObj.open(encoding=globalref.localTextEncoding) as f: for line in f: text = line.strip() if text: level = line.count('\t', 0, len(line) - len(line.lstrip())) node = treenode.TreeNode(formatRef) node.setTitle(text) structure.addNodeDictRef(node) nodeList.append((node, level)) if nodeList and structure.loadChildNodeLevels(nodeList): structure.generateSpots(None) return structure return None def importTableCsvLevels(self): """Import a CSV-delimited table file with level column, header row. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addSpots=False) tableFormat = nodeformat.NodeFormat(_('TABLE'), structure.treeFormats) structure.treeFormats.addTypeIfMissing(tableFormat) nodeList = [] with self.pathObj.open(newline='', encoding=globalref.localTextEncoding) as f: reader = csv.reader(f) try: headings = [self.correctFieldName(name) for name in next(reader)][1:] if not headings: self.errorMessage = (_('No headings found')); return None # abort tableFormat.addFieldList(headings, True, True) for entries in reader: if entries: node = treenode.TreeNode(tableFormat) structure.addNodeDictRef(node) try: level = int(entries.pop(0)) except ValueError: self.errorMessage = (_('Invalid level number on ' 'line {0}'). format(reader.line_num)) return None # abort nodeList.append((node, level)) try: for heading in headings: node.data[heading] = entries.pop(0) except IndexError: pass # fewer entries than headings is OK if entries: self.errorMessage = (_('Too many entries on ' 'Line {0}'). format(reader.line_num)) return None # abort if too few headings except csv.Error: self.errorMessage = (_('Bad CSV format on Line {0}'). format(reader.line_num)) return None # abort if nodeList: if structure.loadChildNodeLevels(nodeList): structure.generateSpots(None) return structure self.errorMessage = (_('Invalid level structure')) return None def importTableCsv(self): """Import a file with a CSV-delimited table with header row. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) tableFormat = nodeformat.NodeFormat(_('TABLE'), structure.treeFormats) structure.treeFormats.addTypeIfMissing(tableFormat) with self.pathObj.open(newline='', encoding=globalref.localTextEncoding) as f: reader = csv.reader(f) try: headings = [self.correctFieldName(name) for name in next(reader)] if not headings: self.errorMessage = (_('No headings found')); return None # abort tableFormat.addFieldList(headings, True, True) for entries in reader: if entries: node = treenode.TreeNode(tableFormat) structure.childList[0].childList.append(node) structure.addNodeDictRef(node) try: for heading in headings: node.data[heading] = entries.pop(0) except IndexError: pass # fewer entries than headings is OK if entries: self.errorMessage = (_('Too many entries on ' 'Line {0}'). format(reader.line_num)) return None # abort if too few headings except csv.Error: self.errorMessage = (_('Bad CSV format on Line {0}'). format(reader.line_num)) return None # abort structure.generateSpots(None) return structure def importTableTabbed(self): """Import a file with a tab-delimited table with header row. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) tableFormat = nodeformat.NodeFormat(_('TABLE'), structure.treeFormats) structure.treeFormats.addTypeIfMissing(tableFormat) with self.pathObj.open(encoding=globalref.localTextEncoding) as f: headings = [self.correctFieldName(name) for name in f.readline().split('\t')] tableFormat.addFieldList(headings, True, True) lineNum = 1 for line in f: lineNum += 1 if line.strip(): entries = line.split('\t') node = treenode.TreeNode(tableFormat) structure.childList[0].childList.append(node) structure.addNodeDictRef(node) try: for heading in headings: node.data[heading] = entries.pop(0) except IndexError: pass # fewer entries than headings is OK if entries: self.errorMessage = (_('Too many entries on Line {0}'). format(lineNum)) return None # abort if too few headings structure.generateSpots(None) return structure @staticmethod def correctFieldName(name): """Return the field name with any illegal characters removed. Arguments: name -- the name to modify """ name = re.sub(r'[^\w_\-.]', '_', name.strip()) if not name: return 'X' if not name[0].isalpha() or name[:3].lower() == 'xml': name = 'X' + name return name def importTextLines(self): """Import a text file, creating one node per line. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) nodeFormat = structure.childList[0].formatRef structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] with self.pathObj.open(encoding=globalref.localTextEncoding) as f: for line in f: line = line.strip() if line: node = treenode.TreeNode(nodeFormat) structure.childList.append(node) structure.addNodeDictRef(node) node.data[nodeformat.defaultFieldName] = line structure.generateSpots(None) return structure def importTextPara(self): """Import a text file, creating one node per paragraph. Blank line delimited. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) nodeFormat = structure.childList[0].formatRef structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] with self.pathObj.open(encoding=globalref.localTextEncoding) as f: text = f.read() paraList = text.split('\n\n') for para in paraList: para = para.strip() if para: node = treenode.TreeNode(nodeFormat) structure.childList.append(node) structure.addNodeDictRef(node) node.data[nodeformat.defaultFieldName] = para structure.generateSpots(None) return structure def importOldTreeLine(self): """Import an old TreeLine File (1.x or 2.x). Return the structure if import is successful, otherwise None. """ tree = ElementTree.ElementTree() try: tree.parse(str(self.pathObj)) except ElementTree.ParseError: tree = None if not tree or not tree.getroot().get('item') == 'y': fileObj = self.pathObj.open('rb') # decompress before decrypt to support TreeLine 1.4 and earlier fileObj, compressed = globalref.mainControl.decompressFile(fileObj) fileObj, encrypted = globalref.mainControl.decryptFile(fileObj) if not fileObj: return None if encrypted and not compressed: fileObj, compressed = (globalref.mainControl. decompressFile(fileObj)) if compressed or encrypted: tree = ElementTree.ElementTree() try: tree.parse(fileObj) except ElementTree.ParseError: tree = None fileObj.close() if not tree or not tree.getroot().get('item') == 'y': return None version = tree.getroot().get('tlversion', '').split('.') try: self.treeLineImportVersion = [int(i) for i in version] except ValueError: pass self.treeLineRootAttrib = self.convertPrintData(tree.getroot().attrib) structure = treestructure.TreeStructure() idRefDict = {} linkList = [] self.loadOldTreeLineNode(tree.getroot(), structure, idRefDict, linkList, None) self.convertOldNodes(structure) linkRe = re.compile(r']*href="#(.*?)"[^>]*>.*?', re.I | re.S) for node, fieldName in linkList: text = node.data[fieldName] startPos = 0 while True: match = linkRe.search(text, startPos) if not match: break newId = idRefDict.get(match.group(1), '') if newId: text = text[:match.start(1)] + newId + text[match.end(1):] startPos = match.start(1) node.data[fieldName] = text structure.generateSpots(None) if nodeformat.FileInfoFormat.typeName in structure.treeFormats: fileFormat = structure.treeFormats[nodeformat.FileInfoFormat. typeName] structure.treeFormats.fileInfoFormat.duplicateFileInfo(fileFormat) del structure.treeFormats[nodeformat.FileInfoFormat.typeName] structure.treeFormats.updateDerivedRefs() for nodeFormat in structure.treeFormats.values(): nodeFormat.updateLineParsing() return structure def loadOldTreeLineNode(self, element, structure, idRefDict, linkList, parent=None): """Recursively load an old TreeLine ElementTree node and its children. Arguments: element -- an ElementTree node structure -- a ref to the new tree structure idRefDict -- a dict to relate old to new unique node IDs linkList -- internal link list ref with (node, fieldname) tuples parent -- the parent TreeNode (None for the root node only) """ try: typeFormat = structure.treeFormats[element.tag] except KeyError: formatData = self.convertOldNodeFormat(element.attrib) typeFormat = nodeformat.NodeFormat(element.tag, structure.treeFormats, formatData) structure.treeFormats[element.tag] = typeFormat self.treeLineOldFieldAttr[typeFormat.name] = {} if element.get('item') == 'y': node = treenode.TreeNode(typeFormat) oldId = element.attrib.get('uniqueid', '') if oldId: idRefDict[oldId] = node.uId if parent: parent.childList.append(node) else: structure.childList.append(node) structure.nodeDict[node.uId] = node cloneAttr = element.attrib.get('clones', '') if cloneAttr: for cloneId in cloneAttr.split(','): if cloneId in idRefDict: cloneNode = structure.nodeDict[idRefDict[cloneId]] node.data = cloneNode.data.copy() break else: # bare format (no nodes) node = None for child in element: if child.get('item') and node: self.loadOldTreeLineNode(child, structure, idRefDict, linkList, node) else: if node and child.text: node.data[child.tag] = child.text if child.get('linkcount'): linkList.append((node, child.tag)) if child.tag not in typeFormat.fieldDict: fieldData = self.convertOldFieldFormat(child.attrib) oldFormatDict = self.treeLineOldFieldAttr[typeFormat.name] oldFormatDict[child.tag] = fieldData typeFormat.addField(child.tag, fieldData) def convertPrintData(self, attrib): """Return JSON print data from old root attributes. Arguments: attrib -- old root print data attributes """ for key in ('printlines', 'printwidowcontrol', 'printportrait'): if key in attrib: attrib[key] = not attrib[key].startswith('n') for key in ('printindentfactor', 'printpaperwidth', 'printpaperheight', 'printheadermargin', 'printfootermargin', 'printcolumnspace'): if key in attrib: attrib[key] = float(attrib[key]) if 'printmargins' in attrib: attrib['printmargins'] = [float(margin) for margin in attrib['printmargins'].split()] if 'printnumcolumns' in attrib: attrib['printnumcolumns'] = int(attrib['printnumcolumns']) return attrib def convertOldNodeFormat(self, attrib): """Return JSON format data from old node format attributes. Arguments: attrib -- old node format attrib dict """ for key in ('spacebetween', 'formathtml', 'bullets', 'tables'): if key in attrib: attrib[key] = attrib[key].startswith('y') attrib['titleline'] = attrib.get('line0', '') lineKeyRe = re.compile(r'line\d+$') lineNums = sorted([int(key[4:]) for key in attrib.keys() if lineKeyRe.match(key)]) if lineNums and lineNums[0] == 0: del lineNums[0] attrib['outputlines'] = [attrib['line{0}'.format(keyNum)] for keyNum in lineNums] if self.treeLineImportVersion < [1, 9]: # for very old TL versions attrib['spacebetween'] = not (self.treeLineRootAttrib. get('nospace', '').startswith('y')) attrib['formathtml'] = not (self.treeLineRootAttrib. get('nohtml', '').startswith('y')) return attrib def convertOldFieldFormat(self, attrib): """Return JSON format data from old field format attributes. Arguments: attrib -- old field node format attrib dict """ fieldType = attrib.get('type', '') if fieldType: attrib['fieldtype'] = fieldType fieldFormat = attrib.get('format', '') if self.treeLineImportVersion < [1, 9]: # for very old TL versions if fieldType in ('URL', 'Path', 'ExecuteLink', 'Email'): attrib['oldfieldtype'] = fieldType fieldType = 'ExternalLink' attrib['fieldtype'] = fieldType if fieldType == 'Date': fieldFormat = fieldFormat.replace('w', 'd') fieldFormat = fieldFormat.replace('m', 'M') if fieldType == 'Time': fieldFormat = fieldFormat.replace('M', 'm') fieldFormat = fieldFormat.replace('s', 'z') fieldFormat = fieldFormat.replace('S', 's') fieldFormat = fieldFormat.replace('AA', 'AP') fieldFormat = fieldFormat.replace('aa', 'ap') if 'lines' in attrib: attrib['lines'] = int(attrib['lines']) if 'sortkeynum' in attrib: attrib['sortkeynum'] = int(attrib['sortkeynum']) if 'sortkeydir' in attrib: attrib['sortkeyfwd'] = not attrib['sortkeydir'].startswith('r') if 'evalhtml' in attrib: attrib['evalhtml'] = attrib['evalhtml'].startswith('y') if fieldType in ('Date', 'Time', 'DateTime'): origFormat = fieldFormat fieldFormat = '' while origFormat: replLen = 4 while replLen > 0: if origFormat[:replLen] in oldDateTimeConv: fieldFormat += oldDateTimeConv[origFormat[:replLen]] origFormat = origFormat[replLen:] break replLen -= 1 if replLen == 0: fieldFormat += origFormat[0] origFormat = origFormat[1:] if fieldFormat: attrib['format'] = fieldFormat return attrib def convertOldNodes(self, structure): """Convert node data to new date and time formats. Arguments: structure -- the ref structure containing the data """ for node in structure.nodeDict.values(): for field in node.formatRef.fields(): text = node.data.get(field.name, '') if text: if field.typeName in ('Date', 'DateTime'): text = text.replace('/', '-') if field.typeName in ('Time', 'DateTime'): text = text + '.000000' if self.treeLineImportVersion < [1, 9]: # very old TL ver oldFormatDict = self.treeLineOldFieldAttr[node. formatRef.name] oldFieldAttr = oldFormatDict[field.name] if (field.typeName == 'Text' and not oldFieldAttr.get('html', '').startswith('y')): text = text.strip() text = xml.sax.saxutils.escape(text) text = text.replace('\n', '
    ') elif (field.typeName == 'ExternalLink' and oldFieldAttr.get('oldfieldtype', '')): oldType = oldFieldAttr['oldfieldtype'] linkAltField = oldFieldAttr.get('linkalt', '') dispName = node.data.get(linkAltField, '') if not dispName: dispName = text if oldType == 'URL': if not urltools.extractScheme(text): text = urltools.replaceScheme('http', text) elif oldType == 'Path': text = urltools.replaceScheme('file', text) elif oldType == 'ExecuteLink': if urltools.isRelative(text): fullPath = urltools.which(text) if fullPath: text = fullPath text = urltools.replaceScheme('file', text) elif oldType == 'Email': text = urltools.replaceScheme('mailto', text) text = '{1}'.format(text, dispName) elif field.typeName == 'InternalLink': linkAltField = oldFieldAttr.get('linkalt', '') dispName = node.data.get(linkAltField, '') if not dispName: dispName = text uniqueId = text.strip().split('\n', 1)[0] uniqueId = uniqueId.replace(' ', '_').lower() uniqueId = re.sub(r'[^a-zA-Z0-9_-]+', '', uniqueId) text = '{1}'.format(uniqueId, dispName) elif field.typeName == 'Picture': text = ''.format(text) node.data[field.name] = text def importTreePad(self): """Import a Treepad file, text nodes only. Return the model if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] tpFormat = structure.treeFormats[treeformats.defaultTypeName] tpFormat.addFieldList([textFieldName], False, True) tpFormat.fieldDict[textFieldName].changeType('SpacedText') try: with self.pathObj.open(encoding=globalref.localTextEncoding) as f: textList = f.read().split(' 5P9i0s8y19Z') except UnicodeDecodeError: with self.pathObj.open(encoding='latin-1') as f: textList = f.read().split(' 5P9i0s8y19Z') except UnicodeDecodeError: return None nodeList = [] for text in textList: text = text.strip() if text: try: text = text.split('', 1)[1].lstrip() lines = text.split('\n') title = lines[0] level = int(lines[1]) lines = lines[2:] except (ValueError, IndexError): return None node = treenode.TreeNode(tpFormat) node.data[nodeformat.defaultFieldName] = title node.data[textFieldName] = '\n'.join(lines) node.level = level nodeList.append(node) structure.addNodeDictRef(node) parentList = [] for node in nodeList: if node.level != 0: parentList = parentList[:node.level] node.parent = parentList[-1] parentList[-1].childList.append(node) parentList.append(node) structure.childList = [nodeList[0]] structure.generateSpots(None) return structure def importXml(self): """Import a non-treeline generic XML file. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure() tree = ElementTree.ElementTree() try: tree.parse(str(self.pathObj)) self.loadXmlNode(tree.getroot(), structure, None) except ElementTree.ParseError: return None for elemFormat in structure.treeFormats.values(): if not elemFormat.getTitleLine(): # fix formats if required elemFormat.changeTitleLine(elemFormat.name) for fieldName in elemFormat.fieldNames(): elemFormat.addOutputLine('{0}="{{*{1}*}}"'. format(fieldName, fieldName)) if not elemFormat.fieldDict: elemFormat.addField(genericXmlTextFieldName) if structure.childList: structure.generateSpots(None) return structure return None def loadXmlNode(self, element, structure, parent=None): """Recursively load a generic XML ElementTree node and its children. Arguments: element -- an XML ElementTree node structure -- a ref to the TreeLine structure parent -- the parent TreeNode (None for the root node only) """ elemFormat = structure.treeFormats.get(element.tag, None) if not elemFormat: elemFormat = nodeformat.NodeFormat(element.tag, structure.treeFormats) structure.treeFormats[element.tag] = elemFormat node = treenode.TreeNode(elemFormat) structure.addNodeDictRef(node) if not parent: parent = structure parent.childList.append(node) if element.text and element.text.strip(): if genericXmlTextFieldName not in elemFormat.fieldDict: elemFormat.addFieldList([genericXmlTextFieldName], True, True) text = element.text.strip() text = xml.sax.saxutils.escape(text) text = text.replace('\n', '
    ') node.data[genericXmlTextFieldName] = text for key, value in element.items(): elemFormat.addFieldIfNew(key) node.data[key] = value for child in element: self.loadXmlNode(child, structure, node) def importOdfText(self): """Import an ODF format text file outline. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure(addDefaults=True, addSpots=False) structure.removeNodeDictRef(structure.childList[0]) structure.childList = [] odfFormat = structure.treeFormats[treeformats.defaultTypeName] odfFormat.addField(textFieldName) odfFormat.changeOutputLines(['{{*{0}*}}'. format(nodeformat.defaultFieldName), '{{*{0}*}}'.format(textFieldName)]) odfFormat.formatHtml = True try: with zipfile.ZipFile(str(self.pathObj), 'r') as f: text = f.read('content.xml') except (zipfile.BadZipFile, KeyError): return None try: rootElement = ElementTree.fromstring(text) except ElementTree.ParseError: return None nameSpace = '{urn:oasis:names:tc:opendocument:xmlns:text:1.0}' headerTag = '{0}h'.format(nameSpace) paraTag = '{0}p'.format(nameSpace) numRegExp = re.compile(r'.*?(\d+)$') parents = [structure] prevLevel = 0 for elem in rootElement.iter(): if elem.tag == headerTag: style = elem.get('{0}style-name'.format(nameSpace), '') try: level = int(numRegExp.match(style).group(1)) except AttributeError: return None if level < 1 or level > prevLevel + 1: return None parents = parents[:level] node = treenode.TreeNode(odfFormat) structure.addNodeDictRef(node) parents[-1].childList.append(node) node.data[nodeformat.defaultFieldName] = ''.join(elem. itertext()) parents.append(node) prevLevel = level elif elem.tag == paraTag: text = ''.join(elem.itertext()) origText = node.data.get(textFieldName, '') if origText: text = '{0}
    {1}'.format(origText, text) node.data[textFieldName] = text structure.generateSpots(None) return structure def createBookmarkFormat(self): """Return a set of node formats for bookmark imports. """ treeFormats = treeformats.TreeFormats() folderFormat = nodeformat.NodeFormat(bookmarkFolderTypeName, treeFormats, addDefaultField=True) folderFormat.iconName = 'folder_3' treeFormats[folderFormat.name] = folderFormat linkFormat = nodeformat.NodeFormat(bookmarkLinkTypeName, treeFormats, addDefaultField=True) linkFormat.addField(bookmarkLinkFieldName, {'fieldtype': 'ExternalLink'}) linkFormat.addOutputLine('{{*{0}*}}'.format(bookmarkLinkFieldName)) linkFormat.iconName = 'bookmark' treeFormats[linkFormat.name] = linkFormat sepFormat = nodeformat.NodeFormat(bookmarkSeparatorTypeName, treeFormats, {'formathtml': True}, True) sepFormat.changeTitleLine('------------------') sepFormat.changeOutputLines(['
    ']) treeFormats[sepFormat.name] = sepFormat return treeFormats def importMozilla(self): """Import an HTML mozilla-format bookmark file. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure() structure.treeFormats = self.createBookmarkFormat() with self.pathObj.open(encoding='utf-8') as f: text = f.read() try: handler = HtmlBookmarkHandler(structure) handler.feed(text) handler.close() except ValueError: return None structure.generateSpots(None) return structure def importXbel(self): """Import an XBEL format bookmark file. Return the structure if import is successful, otherwise None. """ structure = treestructure.TreeStructure() structure.treeFormats = self.createBookmarkFormat() tree = ElementTree.ElementTree() try: tree.parse(str(self.pathObj)) except ElementTree.ParseError: return None self.loadXbelNode(tree.getroot(), structure, None) if structure.childList: structure.generateSpots(None) return structure return None def loadXbelNode(self, element, structure, parent=None): """Recursively load an XBEL ElementTree node and its children. Arguments: element -- an XBEL ElementTree node model -- a ref to the TreeLine model parent -- the parent TreeNode (None for the root node only) """ if element.tag in ('xbel', 'folder'): node = treenode.TreeNode(structure. treeFormats[bookmarkFolderTypeName]) structure.addNodeDictRef(node) if parent: parent.childList.append(node) else: structure.childList.append(node) for child in element: self.loadXbelNode(child, structure, node) elif element.tag == 'bookmark': node = treenode.TreeNode(structure. treeFormats[bookmarkLinkTypeName]) structure.addNodeDictRef(node) parent.childList.append(node) link = element.get('href').strip() if link: node.data[bookmarkLinkFieldName] = ('{1}'. format(link, link)) for child in element: self.loadXbelNode(child, structure, node) elif element.tag == 'title': parent.setTitle(element.text) elif element.tag == 'separator': node = treenode.TreeNode(structure. treeFormats[bookmarkSeparatorTypeName]) structure.addNodeDictRef(node) parent.childList.append(node) else: # unsupported tags pass class HtmlBookmarkHandler(html.parser.HTMLParser): """Handler to parse HTML mozilla bookmark format. """ def __init__(self, structure): """Initialize the HTML parser object. Arguments: structure -- a reference to the tree structure """ super().__init__() self.structure = structure rootNode = treenode.TreeNode(self.structure. treeFormats[bookmarkFolderTypeName]) rootNode.data[nodeformat.defaultFieldName] = _('Bookmarks') self.structure.addNodeDictRef(rootNode) self.structure.childList = [rootNode] self.currentNode = rootNode self.parents = [] self.text = '' def handle_starttag(self, tag, attrs): """Called by the reader at each open tag. Arguments: tag -- the tag label attrs -- any tag attributes """ if tag == 'dt' or tag == 'h1': # start any entry self.text = '' elif tag == 'dl': # start indent self.parents.append(self.currentNode) self.currentNode = None elif tag == 'h3': # start folder if not self.parents: raise ValueError self.currentNode = treenode.TreeNode(self.structure. treeFormats[bookmarkFolderTypeName]) self.structure.addNodeDictRef(self.currentNode) self.parents[-1].childList.append(self.currentNode) elif tag == 'a': # start link if not self.parents: raise ValueError self.currentNode = treenode.TreeNode(self.structure. treeFormats[bookmarkLinkTypeName]) self.structure.addNodeDictRef(self.currentNode) self.parents[-1].childList.append(self.currentNode) for name, value in attrs: if name == 'href': link = '{0}'.format(value) self.currentNode.data[bookmarkLinkFieldName] = link elif tag == 'hr': # separator if not self.parents: raise ValueError node = treenode.TreeNode(self.structure. treeFormats[bookmarkSeparatorTypeName]) self.structure.addNodeDictRef(node) self.parents[-1].childList.append(node) self.currentNode = None def handle_endtag(self, tag): """Called by the reader at each end tag. Arguments: tag -- the tag label """ if tag == 'dl': # end indented section self.parents = self.parents[:-1] self.currentNode = None elif tag == 'h3' or tag == 'a': # end folder or link if not self.currentNode: raise ValueError self.currentNode.data[nodeformat.defaultFieldName] = self.text elif tag == 'h1': # end main title self.structure.childList[0].data[nodeformat. defaultFieldName] = self.text def handle_data(self, data): """Called by the reader to process text. Arguments: data -- the new text """ self.text += data def handle_entityref(self, name): """Convert escaped entity ref to char. Arguments: name -- the name of the escaped entity """ self.text += htmlUnescapeDict.get(name, '') TreeLine-3.2.1/source/matheval.py000066400000000000000000000525031506556630100167130ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # matheval.py, provides a safe eval of mathematical expressions # # TreeLine, an information storage program # Copyright (C) 2020, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import ast import enum import datetime import builtins import fieldformat import gennumber from math import * _nowDateString = 'Now_Date' _nowTimeString = 'Now_Time' _nowDateTimeString = 'Now_Date_Time' def sum(*args): """Override the builtin sum function to handle multiple arguments. Arguments: *args -- lists of numbers or individual numbers """ fullList = [] for arg in args: if hasattr(arg, 'extend'): fullList.extend(arg) else: fullList.append(arg) return builtins.sum(fullList) def max(*args): """Override the builtin max function to expand list arguments. Arguments: *args -- lists of numbers or individual numbers """ fullList = [] for arg in args: if hasattr(arg, 'extend'): fullList.extend(arg) else: fullList.append(arg) if not fullList: return 0 return builtins.max(fullList) def min(*args): """Override the builtin min function to expand list arguments. Arguments: *args -- lists of numbers or individual numbers """ fullList = [] for arg in args: if hasattr(arg, 'extend'): fullList.extend(arg) else: fullList.append(arg) if not fullList: return 0 return builtins.min(fullList) def mean(*args): """Added function to calculate the arithmetic average. Arguments: *args -- lists of numbers or individual numbers """ fullList = [] for arg in args: if hasattr(arg, 'extend'): fullList.extend(arg) else: fullList.append(arg) if not fullList: return 0 return builtins.sum(fullList) / len(fullList) # don't use pow() function from math library pow = builtins.pow def startswith(text, firstText): """Added compare function, returns true if text starts with firstText. Arguments: text -- the string to check firstText -- the starting text """ return str(text).startswith(str(firstText)) def endswith(text, firstText): """Added compare function, returns true if text ends with firstText. Arguments: text -- the string to check firstText -- the ending text """ return str(text).endswith(str(firstText)) def contains(text, innerText): """Added compare function, returns true if text contains innerText. Arguments: text -- the string to check innerText -- the inside text """ return str(innerText) in str(text) def join(sep, *args): """Added text function to combine strings. Arguments: sep -- the separator string *args -- lists of strings or individual strings to combine """ fullList = [] for arg in args: if hasattr(arg, 'extend'): fullList.extend(arg) else: fullList.append(arg) return sep.join([str(i) for i in fullList if str(i)]) def upper(text): """Added text function for upper case. Arguments: text -- the string to modify """ return str(text).upper() def lower(text): """Added text function for lower case. Arguments: text -- the string to modify """ return str(text).lower() def replace(text, oldText, newText): """Added text function to replace strings. Arguments: text -- the string to modify oldText -- the string to be replaced newText -- the replacement string """ return str(text).replace(str(oldText), str(newText)) def count(text): """Added text function to count words. Arguments: text -- the string to analyze """ return len(re.findall(r'\w+', str(text))) _fieldSplitRe = re.compile(r'{\*(\*|\$|&|#|\b)([\w_\-.]+)\*}') class MathEquation: """Class to parse, check, store and evaluate a Math field equation. """ def __init__(self, eqnText=''): """Initialize the MathEquation. Arguments: eqnText -- the text of an equation to be parsed """ self.fieldRefs = [] self.formattedEqnText = '' self.parseEquation(eqnText) def equationText(self): """Return the text representation of the equation. """ fieldNames = ['{{*{0}{1}*}}'.format(ref.tagPrefix, ref.fieldName) for ref in self.fieldRefs] return self.formattedEqnText.format(*fieldNames) def validate(self): """Check if the equation is valid (or empty). Use ones as fake input and use ast to verify legality. Raises a ValueError if the equation is not valid. """ if not self.formattedEqnText: return inputs = [ref.testValue for ref in self.fieldRefs] checker = SafeEvalChecker() try: eqn = self.formattedEqnText.format(*inputs) except IndexError: raise ValueError(_('Illegal "{}" characters')) except KeyError: raise ValueError(_('Invalid field modifiers')) checker.check(eqn) try: result = eval(eqn) if isinstance(result, list): raise TypeError('list result not allowed') except NameError as err: raise ValueError(err) except TypeError as err: if 'list' in str(err) and '&' in [ref.tagPrefix for ref in self.fieldRefs]: msg = _('Child references must be combined in a function') raise ValueError(msg) except ZeroDivisionError: pass def equationValue(self, eqnNode, resultType, zeroValue=0, noMarkup=True): """Return a value for the equation in the given node. Return None if references are invalid. Raise a ValueError for illegal math operations. Arguments: eqnNode -- the node containing the equation to evaluate resultType -- the result type from fieldformat zeroValue -- the value to use for blanks noMarkup -- if true, remove html markup """ zeroBlanks = eqnNode.treeStructureRef().mathZeroBlanks checker = SafeEvalChecker() inputs = [] for ref in self.fieldRefs: inp = ref.referenceValue(eqnNode, zeroBlanks, zeroValue, noMarkup) if inp == None and not zeroBlanks: return None if (resultType == fieldformat.MathResult.number and hasattr(inp, 'format')): try: checker.check(inp) inp = eval(inp) except Exception: inp = repr(inp) else: inp = repr(inp) inputs.append(inp) eqn = self.formattedEqnText.format(*inputs) try: return eval(eqn) except Exception as err: raise ValueError(err) def parseEquation(self, eqnText): """Replace the stored equation by parsing the given text. Creates formatted equation text and a list of field references. Arguments: eqnText -- the text of an equation to be parsed """ self.fieldRefs = [] self.formattedEqnText = _fieldSplitRe.sub(self._replFunc, eqnText) def _replFunc(self, matchObj): """Adds a field ref for each field match from the parser. Returns a string format placeholder as the replacement text. Arguments: matchObj -- the field match object """ fieldRefType = matchObj.group(1) fieldRefName = matchObj.group(2) fieldRefSelector = {'': EquationFieldRef, '*': EquationParentRef, '$': EquationRootRef, '&': EquationChildRef, '#': EquationChildCountRef} fieldRef = fieldRefSelector[fieldRefType](fieldRefName) self.fieldRefs.append(fieldRef) return '{}' # recursive equation ref eval directions EvalDir = enum.IntEnum('EvalDir', 'downward upward optional') class EquationFieldRef: """Class to store and eval individual field references in a Math equation. This base class handles references within the same node. """ tagPrefix = '' testValue = 1 evalDirection = EvalDir.optional def __init__(self, fieldName): """Initialize the field references. Arguments: fieldName -- the name of the referenced field """ self.fieldName = fieldName self.eqnNodeTypeName = '' self.eqnFieldName = '' def referenceValue(self, eqnNode, zeroBlanks=True, zeroValue=0, noMarkup=True): """Return the value of the field referenced in a given node. Return None if blank or doesn't exist and not zeroBlanks, raise a ValueError if it isn't a number. Arguments: eqnNode -- the node containing the equation to evaluate zeroBlanks -- replace blank fields with zeroValue if True zeroValue -- the value to use for blanks noMarkup -- if true, remove html markup """ try: return (eqnNode.formatRef.fieldDict[self.fieldName]. mathValue(eqnNode, zeroBlanks, noMarkup)) except KeyError: if self.fieldName == _nowDateString: return (datetime.date.today() - fieldformat.DateField.refDate).days elif self.fieldName == _nowTimeString: now = datetime.datetime.combine(fieldformat.DateField.refDate, datetime.datetime.now().time()) ref = datetime.datetime.combine(fieldformat.DateField.refDate, fieldformat.TimeField.refTime) return (now - ref).seconds elif self.fieldName == _nowDateTimeString: return (datetime.datetime.now() - fieldformat.DateTimeField.refDateTime).total_seconds() return zeroValue if zeroBlanks else None def dependentEqnNodes(self, refNode): """Return a list of equation node(s) that reference the given node. Arguments: refNode -- the node containing the referenced field """ if refNode.formatRef.name == self.eqnNodeTypeName: return [refNode] return [] class EquationParentRef(EquationFieldRef): """Class to store and eval parent field references in a Math equation. """ tagPrefix = '*' testValue = 1 evalDirection = EvalDir.downward def referenceValue(self, eqnNode, zeroBlanks=True, zeroValue=0, noMarkup=True): """Return the parent field value referenced from a given node. Return None if blank or doesn't exist and not zeroBlanks, raise a ValueError if it isn't a number. Arguments: eqnNode -- the node containing the equation to evaluate zeroBlanks -- replace blank fields with zeroValue if True zeroValue -- the value to use for blanks noMarkup -- if true, remove html markup """ node = eqnNode.spotByNumber(0).parentSpot.nodeRef if not node.formatRef: return zeroValue if zeroBlanks else None try: return (node.formatRef.fieldDict[self.fieldName]. mathValue(node, zeroBlanks, noMarkup)) except KeyError: return zeroValue if zeroBlanks else None def dependentEqnNodes(self, refNode): """Return a list of equation node(s) that reference the given node. Arguments: refNode -- the node containing the referenced field """ return [node for node in refNode.childList if node.formatRef.name == self.eqnNodeTypeName] class EquationRootRef(EquationFieldRef): """Class to store and eval root node field references in a Math equation. """ tagPrefix = '$' testValue = 1 evalDirection = EvalDir.downward def referenceValue(self, eqnNode, zeroBlanks=True, zeroValue=0, noMarkup=True): """Return the root field value referenced from a given node. Return None if blank or doesn't exist and not zeroBlanks, raise a ValueError if it isn't a number. Arguments: eqnNode -- the node containing the equation to evaluate zeroBlanks -- replace blank fields with zeroValue if True zeroValue -- the value to use for blanks noMarkup -- if true, remove html markup """ node = eqnNode.spotByNumber(0).spotChain()[0].nodeRef try: return (node.formatRef.fieldDict[self.fieldName]. mathValue(node, zeroBlanks, noMarkup)) except KeyError: return zeroValue if zeroBlanks else None def dependentEqnNodes(self, refNode): """Return a list of equation node(s) that reference the given node. Arguments: refNode -- the node containing the referenced field """ if 1 not in {len(spot.spotChain()) for spot in refNode.spotRefs}: # not a root node return [] refs = [node for node in refNode.descendantGen() if node.formatRef.name == self.eqnNodeTypeName] if refs and refs[0] is refNode: refs = refs[1:] return refs class EquationChildRef(EquationFieldRef): """Class to store and eval child field references in a Math equation. """ tagPrefix = '&' testValue = [1] evalDirection = EvalDir.upward def referenceValue(self, eqnNode, zeroBlanks=True, zeroValue=0, noMarkup=True): """Return a list with child field values referenced from a given node. Return None if there are blanks and zeroBlanks is false, raise a ValueError if any aren't a number. Arguments: eqnNode -- the node containing the equation to evaluate zeroBlanks -- replace blank fields with zeroValue if True zeroValue -- the value to use for blanks """ result = [] for node in eqnNode.childList: try: num = (node.formatRef.fieldDict[self.fieldName]. mathValue(node, zeroBlanks, noMarkup)) if num == None: return None result.append(num) except KeyError: if not zeroBlanks: return None if not result: result = [zeroValue] return result def dependentEqnNodes(self, refNode): """Return a list of equation node(s) that reference the given node. Arguments: refNode -- the node containing the referenced field """ node = refNode.spotByNumber(0).parentSpot.nodeRef if node.formatRef and node.formatRef.name == self.eqnNodeTypeName: return [node] return [] class EquationChildCountRef(EquationFieldRef): """Class to store and eval child count references in a Math equation. """ tagPrefix = '#' testValue = 1 evalDirection = EvalDir.optional def referenceValue(self, eqnNode, zeroBlanks=True, zeroValue=0, noMarkup=True): """Return the child count referenced from the given node. Arguments: eqnNode -- the node containing the equation to evaluate zeroBlanks -- replace blank fields with zeroValue if True zeroValue -- the value to use for blanks noMarkup -- if true, remove html markup """ return len(eqnNode.childList) def dependentEqnNodes(self, refNode): """Return a list of equation node(s) that reference the given node. Arguments: refNode -- the node containing the referenced field """ node = refNode.spotByNumber(0).parentSpot.nodeRef if node and node.formatRef.name == self.eqnNodeTypeName: return [node] return [] class RecursiveEqnRef: """Class to store a references to other equations in a tree structure. Resolves sequence and direction of global evaluations. """ recursiveRefDict = {} def __init__(self, eqnTypeName, eqnField): """Initialize the RecursiveEquationRef. Arguments: eqnTypeName -- the type format name contining the equation field eqnField -- the field with the equation to eval for other eqn refs """ self.eqnTypeName = eqnTypeName self.eqnField = eqnField self.evalSequence = 0 self.evalDirection = EvalDir.optional def setPriorities(self, visitedFields=None): """Recursively set sequence and direction for evaluation. Arguments: visitedFields -- set of used eqn field names to check circular refs """ if self.evalSequence != 0: return if visitedFields == None: visitedFields = set() visitedFields = visitedFields.copy() visitedFields.add(self.eqnField.name) self.evalSequence = 1 for fieldRef in self.eqnField.equation.fieldRefs: if (fieldRef.fieldName in visitedFields and fieldRef.tagPrefix != '#' and (self.eqnField.name != fieldRef.fieldName or fieldRef.evalDirection == EvalDir.optional)): raise CircularMathError() for eqnRef in self.recursiveRefDict.get(fieldRef.fieldName, []): eqnRef.setPriorities(visitedFields) if eqnRef.evalSequence >= self.evalSequence: self.evalDirection = fieldRef.evalDirection self.evalSequence = eqnRef.evalSequence if (self.evalDirection != eqnRef.evalDirection or self.evalDirection == EvalDir.optional): self.evalSequence += 1 def __lt__(self, other): """Use sequence and direction as comparison keys for sorting. Arguments: other -- the equation ref to compare """ return ((self.evalSequence, self.evalDirection) < (other.evalSequence, other.evalDirection)) class CircularMathError(Exception): """Exception raised when circular references are found in math fields. """ pass allowedFunctions = set(['abs', 'float', 'int', 'len', 'max', 'min', 'pow', 'round', 'sum', 'mean', 'ceil', 'fabs', 'factorial', 'floor', 'fmod', 'fsum', 'trunc', 'exp', 'log', 'log10', 'pow', 'sqrt', 'acos', 'asin', 'atan', 'cos', 'sin', 'tan', 'hypot', 'degrees', 'radians', 'pi', 'e', 'startswith', 'endswith', 'contains', 'join', 'upper', 'lower', 'replace', 'count']) allowedNodeTypes = set(['Module', 'Expr', 'Name', 'NameConstant', 'Constant', 'Load', 'IfExp', 'Compare', 'Num', 'Str', 'Tuple', 'List', 'BinOp', 'UnaryOp', 'Add', 'Sub', 'Mult', 'Div', 'Mod', 'Pow', 'FloorDiv', 'Invert', 'Not', 'UAdd', 'USub', 'Eq', 'NotEq', 'Lt', 'LtE', 'Gt', 'GtE', 'Is', 'IsNot', 'In', 'NotIn', 'BoolOp', 'And', 'Or']) class SafeEvalChecker(ast.NodeVisitor): """Class to check that only safe functions are used in an eval expression. Raises a ValueError if unsafe or non-numeric operations are present. Ref. stackoverflow.com questions 10661079 and 12523516 """ def check(self, expr): """Check the given expression for non-numeric operations. Arguments: expr -- the expression string to check """ try: tree = ast.parse(expr) except SyntaxError: raise ValueError(_('Illegal syntax in equation')) self.visit(tree) def visit_Call(self, node): """Check for allowed functions only. Arguments: node -- the ast node being checked """ if node.func.id in allowedFunctions: super().generic_visit(node) else: raise ValueError(_('Illegal function present: {0}'). format(node.func.id)) def generic_visit(self, node): """Check for allowed node types and operators. Arguments: node -- the ast node being checked """ if type(node).__name__ in allowedNodeTypes: super().generic_visit(node) else: raise ValueError(_('Illegal object type or operator: {0}'). format(type(node).__name__)) if __name__ == '__main__': checker = SafeEvalChecker() try: print('Enter expression: ') expr = input() checker.check(expr) except ValueError as err: print(err) else: print(eval(expr)) TreeLine-3.2.1/source/miscdialogs.py000066400000000000000000002356461506556630100174230ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # miscdialogs.py, provides classes for various control dialogs # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import enum import re import sys import operator import collections import datetime import platform import traceback from PyQt6.QtCore import Qt, pyqtSignal, PYQT_VERSION_STR, qVersion from PyQt6.QtGui import QFont, QKeySequence, QTextDocument, QTextOption from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QButtonGroup, QCheckBox, QComboBox, QDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QListWidget, QListWidgetItem, QMenu, QMessageBox, QPlainTextEdit, QPushButton, QRadioButton, QScrollArea, QSpinBox, QTabWidget, QTextEdit, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget) import options import printdialogs import undo import globalref try: from __main__ import __version__ except ImportError: __version__ = '' class RadioChoiceDialog(QDialog): """Dialog for choosing between a list of text items (radio buttons). Dialog title, group heading, button text and return text can be set. """ def __init__(self, title, heading, choiceList, parent=None): """Create the radio choice dialog. Arguments: title -- the window title heading -- the groupbox text choiceList -- tuples of button text and return values parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(title) topLayout = QVBoxLayout(self) self.setLayout(topLayout) groupBox = QGroupBox(heading) topLayout.addWidget(groupBox) groupLayout = QVBoxLayout(groupBox) self.buttonGroup = QButtonGroup(self) for text, value in choiceList: if value != None: button = QRadioButton(text) button.returnValue = value groupLayout.addWidget(button) self.buttonGroup.addButton(button) else: # add heading if no return value label = QLabel('{0}:'.format(text)) groupLayout.addWidget(label) self.buttonGroup.buttons()[0].setChecked(True) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) groupBox.setFocus() def addLabelBox(self, heading, text): """Add a group box with text above the radio button group. Arguments: heading -- the groupbox text text - the label text """ labelBox = QGroupBox(heading) self.layout().insertWidget(0, labelBox) labelLayout = QVBoxLayout(labelBox) label = QLabel(text) labelLayout.addWidget(label) def selectedButton(self): """Return the value of the selected button. """ return self.buttonGroup.checkedButton().returnValue class FieldSelectDialog(QDialog): """Dialog for selecting a sequence from a list of field names. """ def __init__(self, title, heading, fieldList, parent=None): """Create the field select dialog. Arguments: title -- the window title heading -- the groupbox text fieldList -- the list of field names to select parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(title) self.selectedFields = [] topLayout = QVBoxLayout(self) self.setLayout(topLayout) groupBox = QGroupBox(heading) topLayout.addWidget(groupBox) groupLayout = QVBoxLayout(groupBox) self.listView = QTreeWidget() groupLayout.addWidget(self.listView) self.listView.setHeaderLabels(['#', _('Fields')]) self.listView.setRootIsDecorated(False) self.listView.setSortingEnabled(False) self.listView.setSelectionMode(QAbstractItemView.SelectionMode. MultiSelection) for field in fieldList: QTreeWidgetItem(self.listView, ['', field]) self.listView.resizeColumnToContents(0) self.listView.resizeColumnToContents(1) self.listView.itemSelectionChanged.connect(self.updateSelectedFields) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) self.okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(self.okButton) self.okButton.clicked.connect(self.accept) self.okButton.setEnabled(False) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.listView.setFocus() def updateSelectedFields(self): """Update the TreeView and the list of selected fields. """ itemList = [self.listView.topLevelItem(i) for i in range(self.listView.topLevelItemCount())] for item in itemList: if item.isSelected(): if item.text(1) not in self.selectedFields: self.selectedFields.append(item.text(1)) elif item.text(1) in self.selectedFields: self.selectedFields.remove(item.text(1)) for item in itemList: if item.isSelected(): item.setText(0, str(self.selectedFields.index(item.text(1)) + 1)) else: item.setText(0, '') self.okButton.setEnabled(len(self.selectedFields)) class FilePropertiesDialog(QDialog): """Dialog for setting file parameters like compression and encryption. """ def __init__(self, localControl, parent=None): """Create the file properties dialog. Arguments: localControl -- a reference to the file's local control parent -- the parent window """ super().__init__(parent) self.localControl = localControl self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('File Properties')) topLayout = QVBoxLayout(self) self.setLayout(topLayout) groupBox = QGroupBox(_('File Storage')) topLayout.addWidget(groupBox) groupLayout = QVBoxLayout(groupBox) self.compressCheck = QCheckBox(_('&Use file compression')) self.compressCheck.setChecked(localControl.compressed) groupLayout.addWidget(self.compressCheck) self.encryptCheck = QCheckBox(_('Use file &encryption')) self.encryptCheck.setChecked(localControl.encrypted) groupLayout.addWidget(self.encryptCheck) groupBox = QGroupBox(_('Spell Check')) topLayout.addWidget(groupBox) groupLayout = QHBoxLayout(groupBox) label = QLabel(_('Language code or\ndictionary (optional)')) groupLayout.addWidget(label) self.spellCheckEdit = QLineEdit() self.spellCheckEdit.setText(self.localControl.spellCheckLang) groupLayout.addWidget(self.spellCheckEdit) groupBox = QGroupBox(_('Math Fields')) topLayout.addWidget(groupBox) groupLayout = QVBoxLayout(groupBox) self.zeroBlanks = QCheckBox(_('&Treat blank fields as zeros')) self.zeroBlanks.setChecked(localControl.structure.mathZeroBlanks) groupLayout.addWidget(self.zeroBlanks) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) def accept(self): """Store the results. """ if (self.localControl.compressed != self.compressCheck.isChecked() or self.localControl.encrypted != self.encryptCheck.isChecked() or self.localControl.spellCheckLang != self.spellCheckEdit.text() or self.localControl.structure.mathZeroBlanks != self.zeroBlanks.isChecked()): undo.ParamUndo(self.localControl.structure.undoList, [(self.localControl, 'compressed'), (self.localControl, 'encrypted'), (self.localControl, 'spellCheckLang'), (self.localControl.structure, 'mathZeroBlanks')]) self.localControl.compressed = self.compressCheck.isChecked() self.localControl.encrypted = self.encryptCheck.isChecked() self.localControl.spellCheckLang = self.spellCheckEdit.text() self.localControl.structure.mathZeroBlanks = (self.zeroBlanks. isChecked()) super().accept() else: super().reject() class PasswordDialog(QDialog): """Dialog for password entry and optional re-entry. """ remember = True def __init__(self, retype=True, fileLabel='', parent=None): """Create the password dialog. Arguments: retype -- require a 2nd password entry if True fileLabel -- file name to show if given parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Encrypted File Password')) self.password = '' topLayout = QVBoxLayout(self) self.setLayout(topLayout) if fileLabel: prompt = _('Type Password for "{0}":').format(fileLabel) else: prompt = _('Type Password:') self.editors = [self.addEditor(prompt, topLayout)] self.editors[0].setFocus() if retype: self.editors.append(self.addEditor(_('Re-Type Password:'), topLayout)) self.editors[0].returnPressed.connect(self.editors[1].setFocus) self.editors[-1].returnPressed.connect(self.accept) self.rememberCheck = QCheckBox(_('Remember password during this ' 'session')) self.rememberCheck.setChecked(PasswordDialog.remember) topLayout.addWidget(self.rememberCheck) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) okButton = QPushButton(_('&OK')) okButton.setAutoDefault(False) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) cancelButton.setAutoDefault(False) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) def addEditor(self, labelText, layout): """Add a password editor to this dialog and return it. Arguments: labelText -- the text for the label layout -- the layout to append it """ label = QLabel(labelText) layout.addWidget(label) editor = QLineEdit() editor.setEchoMode(QLineEdit.EchoMode.Password) layout.addWidget(editor) return editor def accept(self): """Check for valid password and store the result. """ self.password = self.editors[0].text() PasswordDialog.remember = self.rememberCheck.isChecked() if not self.password: QMessageBox.warning(self, 'TreeLine', _('Zero-length passwords are not permitted')) elif len(self.editors) > 1 and self.editors[1].text() != self.password: QMessageBox.warning(self, 'TreeLine', _('Re-typed password did not match')) else: super().accept() for editor in self.editors: editor.clear() self.editors[0].setFocus() class ExtModDialog(QDialog): """Dialog for how to hanlde a file that was externally modified. """ def __init__(self, modTime, parent=None): """Cretate the external mod dialog. Arguments: modTime -- the datetime of the external mod parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Externally Modified File')) topLayout = QVBoxLayout(self) self.setLayout(topLayout) label = QLabel(_('File was externally modified at {}'). format(modTime.isoformat(' ', 'seconds'))) topLayout.addWidget(label) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) overwriteButton = QPushButton(_('&Overwrite File')) overwriteButton.setAutoDefault(False) ctrlLayout.addWidget(overwriteButton) overwriteButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel Save')) cancelButton.setAutoDefault(False) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) class TemplateFileItem: """Helper class to store template paths and info. """ nameExp = re.compile(r'(\d+)([a-zA-Z]+?)_(.+)') def __init__(self, pathObj): """Initialize the path. Arguments: pathObj -- the full path object """ self.pathObj = pathObj self.number = sys.maxsize self.name = '' self.displayName = '' self.langCode = '' if pathObj: self.name = pathObj.stem match = TemplateFileItem.nameExp.match(self.name) if match: num, self.langCode, self.name = match.groups() self.number = int(num) self.displayName = self.name.replace('_', ' ') def sortKey(self): """Return a key for sorting the items by number then name. """ return (self.number, self.displayName) def __eq__(self, other): """Comparison to detect equivalent items. Arguments: other -- the TemplateFileItem to compare """ return (self.displayName == other.displayName and self.langCode == other.langCode) def __hash__(self): """Return a hash code for use in sets and dictionaries. """ return hash((self.langCode, self.displayName)) class TemplateFileDialog(QDialog): """Dialog for listing available template files. """ def __init__(self, title, heading, searchPaths, addDefault=True, parent=None): """Create the template dialog. Arguments: title -- the window title heading -- the groupbox text searchPaths -- list of path objects with available templates addDefault -- if True, add a default (no path) entry parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(title) self.templateItems = [] if addDefault: item = TemplateFileItem(None) item.number = -1 item.displayName = _('Default - Single Line Text') self.templateItems.append(item) topLayout = QVBoxLayout(self) self.setLayout(topLayout) groupBox = QGroupBox(heading) topLayout.addWidget(groupBox) boxLayout = QVBoxLayout(groupBox) self.listBox = QListWidget() boxLayout.addWidget(self.listBox) self.listBox.itemDoubleClicked.connect(self.accept) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) self.okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(self.okButton) self.okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.readTemplates(searchPaths) self.loadListBox() def readTemplates(self, searchPaths): """Read template file paths into the templateItems list. Arguments: searchPaths -- list of path objects with available templates """ templateItems = set() for path in searchPaths: for templatePath in path.glob('*.trln'): templateItem = TemplateFileItem(templatePath) if templateItem not in templateItems: templateItems.add(templateItem) availLang = set([item.langCode for item in templateItems]) if len(availLang) > 1: lang = 'en' if globalref.lang[:2] in availLang: lang = globalref.lang[:2] templateItems = [item for item in templateItems if item.langCode == lang or not item.langCode] self.templateItems.extend(list(templateItems)) self.templateItems.sort(key = operator.methodcaller('sortKey')) def loadListBox(self): """Load the list box with items from the templateItems list. """ self.listBox.clear() self.listBox.addItems([item.displayName for item in self.templateItems]) self.listBox.setCurrentRow(0) self.okButton.setEnabled(self.listBox.count() > 0) def selectedPath(self): """Return the path object from the selected item. """ item = self.templateItems[self.listBox.currentRow()] return item.pathObj def selectedName(self): """Return the displayed name with underscores from the selected item. """ item = self.templateItems[self.listBox.currentRow()] return item.name class ExceptionDialog(QDialog): """Dialog for showing debug info from an unhandled exception. """ def __init__(self, excType, value, tb, parent=None): """Initialize the exception dialog. Arguments: excType -- execption class value -- execption error text tb -- the traceback object """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowStaysOnTopHint) self.setWindowTitle(_('TreeLine - Serious Error')) topLayout = QVBoxLayout(self) self.setLayout(topLayout) label = QLabel(_('A serious error has occurred. TreeLine could be ' 'in an unstable state.\n' 'Recommend saving any file changes under another ' 'filename and restart TreeLine.\n\n' 'The debugging info shown below can be copied ' 'and emailed to doug101@bellz.org along with\n' 'an explanation of the circumstances.\n')) topLayout.addWidget(label) textBox = QTextEdit() textBox.setReadOnly(True) pyVersion = '.'.join([repr(num) for num in sys.version_info[:3]]) textLines = ['When: {0}\n'.format(datetime.datetime.now(). isoformat(' ')), 'TreeLine Version: {0}\n'.format(__version__), 'Python Version: {0}\n'.format(pyVersion), 'Qt Version: {0}\n'.format(qVersion()), 'PyQt Version: {0}\n'.format(PYQT_VERSION_STR), 'OS: {0}\n'.format(platform.platform()), '\n'] textLines.extend(traceback.format_exception(excType, value, tb)) textBox.setPlainText(''.join(textLines)) topLayout.addWidget(textBox) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) closeButton = QPushButton(_('&Close')) ctrlLayout.addWidget(closeButton) closeButton.clicked.connect(self.close) FindScope = enum.IntEnum('FindScope', 'fullData titlesOnly') FindType = enum.IntEnum('FindType', 'keyWords fullWords fullPhrase regExp') class FindFilterDialog(QDialog): """Dialog for searching for text within tree titles and data. """ dialogShown = pyqtSignal(bool) def __init__(self, isFilterDialog=False, parent=None): """Initialize the find dialog. Arguments: isFilterDialog -- True for filter dialog, False for find dialog parent -- the parent window """ super().__init__(parent) self.isFilterDialog = isFilterDialog self.setAttribute(Qt.WidgetAttribute.WA_QuitOnClose, False) self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowStaysOnTopHint) topLayout = QVBoxLayout(self) self.setLayout(topLayout) textBox = QGroupBox(_('&Search Text')) topLayout.addWidget(textBox) textLayout = QVBoxLayout(textBox) self.textEntry = QLineEdit() textLayout.addWidget(self.textEntry) self.textEntry.textEdited.connect(self.updateAvail) horizLayout = QHBoxLayout() topLayout.addLayout(horizLayout) whatBox = QGroupBox(_('What to Search')) horizLayout.addWidget(whatBox) whatLayout = QVBoxLayout(whatBox) self.whatButtons = QButtonGroup(self) button = QRadioButton(_('Full &data')) self.whatButtons.addButton(button, FindScope.fullData) whatLayout.addWidget(button) button = QRadioButton(_('&Titles only')) self.whatButtons.addButton(button, FindScope.titlesOnly) whatLayout.addWidget(button) self.whatButtons.button(FindScope.fullData).setChecked(True) howBox = QGroupBox(_('How to Search')) horizLayout.addWidget(howBox) howLayout = QVBoxLayout(howBox) self.howButtons = QButtonGroup(self) button = QRadioButton(_('&Key words')) self.howButtons.addButton(button, FindType.keyWords) howLayout.addWidget(button) button = QRadioButton(_('Key full &words')) self.howButtons.addButton(button, FindType.fullWords) howLayout.addWidget(button) button = QRadioButton(_('F&ull phrase')) self.howButtons.addButton(button, FindType.fullPhrase) howLayout.addWidget(button) button = QRadioButton(_('&Regular expression')) self.howButtons.addButton(button, FindType.regExp) howLayout.addWidget(button) self.howButtons.button(FindType.keyWords).setChecked(True) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) if not self.isFilterDialog: self.setWindowTitle(_('Find')) self.previousButton = QPushButton(_('Find &Previous')) ctrlLayout.addWidget(self.previousButton) self.previousButton.clicked.connect(self.findPrevious) self.nextButton = QPushButton(_('Find &Next')) self.nextButton.setDefault(True) ctrlLayout.addWidget(self.nextButton) self.nextButton.clicked.connect(self.findNext) self.resultLabel = QLabel() topLayout.addWidget(self.resultLabel) else: self.setWindowTitle(_('Filter')) self.filterButton = QPushButton(_('&Filter')) ctrlLayout.addWidget(self.filterButton) self.filterButton.clicked.connect(self.startFilter) self.endFilterButton = QPushButton(_('&End Filter')) ctrlLayout.addWidget(self.endFilterButton) self.endFilterButton.clicked.connect(self.endFilter) closeButton = QPushButton(_('&Close')) ctrlLayout.addWidget(closeButton) closeButton.clicked.connect(self.close) self.updateAvail('') def selectAllText(self): """Select all line edit text to prepare for a new entry. """ self.textEntry.selectAll() self.textEntry.setFocus() def updateAvail(self, text='', fileChange=False): """Make find buttons available if search text exists. Arguments: text -- placeholder for signal text (not used) fileChange -- True if window changed while dialog open """ hasEntry = len(self.textEntry.text().strip()) > 0 if not self.isFilterDialog: self.previousButton.setEnabled(hasEntry) self.nextButton.setEnabled(hasEntry) self.resultLabel.setText('') else: window = globalref.mainControl.activeControl.activeWindow if fileChange and window.treeFilterView: filterView = window.treeFilterView self.textEntry.setText(filterView.filterStr) self.whatButtons.button(filterView.filterWhat).setChecked(True) self.howButtons.button(filterView.filterHow).setChecked(True) self.filterButton.setEnabled(hasEntry) self.endFilterButton.setEnabled(window.treeFilterView != None) def find(self, forward=True): """Find another match in the indicated direction. Arguments: forward -- next if True, previous if False """ self.resultLabel.setText('') text = self.textEntry.text() titlesOnly = self.whatButtons.checkedId() == (FindScope.titlesOnly) control = globalref.mainControl.activeControl if self.howButtons.checkedId() == FindType.regExp: try: regExp = re.compile(text) except re.error: QMessageBox.warning(self, 'TreeLine', _('Error - invalid regular expression')) return result = control.findNodesByRegExp([regExp], titlesOnly, forward) elif self.howButtons.checkedId() == FindType.fullWords: regExpList = [] for word in text.lower().split(): regExpList.append(re.compile(r'(?i)\b{}\b'. format(re.escape(word)))) result = control.findNodesByRegExp(regExpList, titlesOnly, forward) elif self.howButtons.checkedId() == FindType.keyWords: wordList = text.lower().split() result = control.findNodesByWords(wordList, titlesOnly, forward) else: # full phrase wordList = [text.lower().strip()] result = control.findNodesByWords(wordList, titlesOnly, forward) if not result: self.resultLabel.setText(_('Search string "{0}" not found'). format(text)) def findPrevious(self): """Find the previous match. """ self.find(False) def findNext(self): """Find the next match. """ self.find(True) def startFilter(self): """Start filtering nodes. """ if self.howButtons.checkedId() == FindType.regExp: try: re.compile(self.textEntry.text()) except re.error: QMessageBox.warning(self, 'TreeLine', _('Error - invalid regular expression')) return filterView = (globalref.mainControl.activeControl.activeWindow. filterView()) filterView.filterWhat = self.whatButtons.checkedId() filterView.filterHow = self.howButtons.checkedId() filterView.filterStr = self.textEntry.text() filterView.updateContents() self.updateAvail() def endFilter(self): """Stop filtering nodes. """ globalref.mainControl.activeControl.activeWindow.removeFilterView() self.updateAvail() def closeEvent(self, event): """Signal that the dialog is closing. Arguments: event -- the close event """ self.dialogShown.emit(False) def reject(self): """Handle use of escape key to close this dialog. """ self.close() FindReplaceType = enum.IntEnum('FindReplaceType', 'anyMatch fullWord regExp') class FindReplaceDialog(QDialog): """Dialog for finding and replacing text in the node data. """ dialogShown = pyqtSignal(bool) def __init__(self, parent=None): """Initialize the find and replace dialog. Arguments: parent -- the parent window """ super().__init__(parent) self.setAttribute(Qt.WidgetAttribute.WA_QuitOnClose, False) self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowStaysOnTopHint) self.setWindowTitle(_('Find and Replace')) self.matchedSpot = None topLayout = QGridLayout(self) self.setLayout(topLayout) textBox = QGroupBox(_('&Search Text')) topLayout.addWidget(textBox, 0, 0) textLayout = QVBoxLayout(textBox) self.textEntry = QLineEdit() textLayout.addWidget(self.textEntry) self.textEntry.textEdited.connect(self.clearMatch) replaceBox = QGroupBox(_('Replacement &Text')) topLayout.addWidget(replaceBox, 0, 1) replaceLayout = QVBoxLayout(replaceBox) self.replaceEntry = QLineEdit() replaceLayout.addWidget(self.replaceEntry) howBox = QGroupBox(_('How to Search')) topLayout.addWidget(howBox, 1, 0, 2, 1) howLayout = QVBoxLayout(howBox) self.howButtons = QButtonGroup(self) button = QRadioButton(_('Any &match')) self.howButtons.addButton(button, FindReplaceType.anyMatch) howLayout.addWidget(button) button = QRadioButton(_('Full &words')) self.howButtons.addButton(button, FindReplaceType.fullWord) howLayout.addWidget(button) button = QRadioButton(_('Re&gular expression')) self.howButtons.addButton(button, FindReplaceType.regExp) howLayout.addWidget(button) self.howButtons.button(FindReplaceType.anyMatch).setChecked(True) self.howButtons.buttonClicked.connect(self.clearMatch) typeBox = QGroupBox(_('&Node Type')) topLayout.addWidget(typeBox, 1, 1) typeLayout = QVBoxLayout(typeBox) self.typeCombo = QComboBox() typeLayout.addWidget(self.typeCombo) self.typeCombo.currentIndexChanged.connect(self.loadFieldNames) fieldBox = QGroupBox(_('N&ode Fields')) topLayout.addWidget(fieldBox, 2, 1) fieldLayout = QVBoxLayout(fieldBox) self.fieldCombo = QComboBox() fieldLayout.addWidget(self.fieldCombo) self.fieldCombo.currentIndexChanged.connect(self.clearMatch) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout, 3, 0, 1, 2) self.previousButton = QPushButton(_('Find &Previous')) ctrlLayout.addWidget(self.previousButton) self.previousButton.clicked.connect(self.findPrevious) self.nextButton = QPushButton(_('&Find Next')) self.nextButton.setDefault(True) ctrlLayout.addWidget(self.nextButton) self.nextButton.clicked.connect(self.findNext) self.replaceButton = QPushButton(_('&Replace')) ctrlLayout.addWidget(self.replaceButton) self.replaceButton.clicked.connect(self.replace) self.replaceAllButton = QPushButton(_('Replace &All')) ctrlLayout.addWidget(self.replaceAllButton) self.replaceAllButton.clicked.connect(self.replaceAll) closeButton = QPushButton(_('&Close')) ctrlLayout.addWidget(closeButton) closeButton.clicked.connect(self.close) self.resultLabel = QLabel() topLayout.addWidget(self.resultLabel, 4, 0, 1, 2) self.loadTypeNames() self.updateAvail() def updateAvail(self): """Set find & replace buttons available if search text & matches exist. """ hasEntry = (len(self.textEntry.text().strip()) > 0 or self.howButtons.checkedId() == FindReplaceType.anyMatch) self.previousButton.setEnabled(hasEntry) self.nextButton.setEnabled(hasEntry) match = bool(self.matchedSpot and self.matchedSpot is globalref.mainControl.activeControl. currentSelectionModel().currentSpot()) self.replaceButton.setEnabled(match) self.replaceAllButton.setEnabled(match) self.resultLabel.setText('') def clearMatch(self): """Remove reference to matched node if search criteria changes. """ self.matchedSpot = None globalref.mainControl.activeControl.findReplaceSpotRef = (None, 0) self.updateAvail() def loadTypeNames(self): """Load format type names into combo box. """ origTypeName = self.typeCombo.currentText() nodeFormats = globalref.mainControl.activeControl.structure.treeFormats self.typeCombo.blockSignals(True) self.typeCombo.clear() typeNames = nodeFormats.typeNames() self.typeCombo.addItems([_('[All Types]')] + typeNames) origPos = self.typeCombo.findText(origTypeName) if origPos >= 0: self.typeCombo.setCurrentIndex(origPos) self.typeCombo.blockSignals(False) self.loadFieldNames() def loadFieldNames(self): """Load field names into combo box. """ origFieldName = self.fieldCombo.currentText() nodeFormats = globalref.mainControl.activeControl.structure.treeFormats typeName = self.typeCombo.currentText() fieldNames = [] if typeName.startswith('['): for typeName in nodeFormats.typeNames(): for fieldName in nodeFormats[typeName].fieldNames(): if fieldName not in fieldNames: fieldNames.append(fieldName) else: fieldNames.extend(nodeFormats[typeName].fieldNames()) self.fieldCombo.clear() self.fieldCombo.addItems([_('[All Fields]')] + fieldNames) origPos = self.fieldCombo.findText(origFieldName) if origPos >= 0: self.fieldCombo.setCurrentIndex(origPos) self.matchedSpot = None self.updateAvail() def findParameters(self): """Create search parameters based on the dialog settings. Return a tuple of searchText, regExpObj, typeName, and fieldName. """ text = self.textEntry.text() searchText = '' regExpObj = None if self.howButtons.checkedId() == FindReplaceType.anyMatch: searchText = text.lower().strip() elif self.howButtons.checkedId() == FindReplaceType.fullWord: regExpObj = re.compile(r'(?i)\b{}\b'.format(re.escape(text))) else: regExpObj = re.compile(text) typeName = self.typeCombo.currentText() if typeName.startswith('['): typeName = '' fieldName = self.fieldCombo.currentText() if fieldName.startswith('['): fieldName = '' return (searchText, regExpObj, typeName, fieldName) def find(self, forward=True): """Find another match in the indicated direction. Arguments: forward -- next if True, previous if False """ self.matchedSpot = None try: searchText, regExpObj, typeName, fieldName = self.findParameters() except re.error: QMessageBox.warning(self, 'TreeLine', _('Error - invalid regular expression')) self.updateAvail() return control = globalref.mainControl.activeControl if control.findNodesForReplace(searchText, regExpObj, typeName, fieldName, forward): self.matchedSpot = control.currentSelectionModel().currentSpot() self.updateAvail() else: self.updateAvail() self.resultLabel.setText(_('Search text "{0}" not found'). format(self.textEntry.text())) def findPrevious(self): """Find the previous match. """ self.find(False) def findNext(self): """Find the next match. """ self.find(True) def replace(self): """Replace the currently found text. """ searchText, regExpObj, typeName, fieldName = self.findParameters() replaceText = self.replaceEntry.text() control = globalref.mainControl.activeControl if control.replaceInCurrentNode(searchText, regExpObj, typeName, fieldName, replaceText): self.find() else: QMessageBox.warning(self, 'TreeLine', _('Error - replacement failed')) self.matchedSpot = None self.updateAvail() def replaceAll(self): """Replace all text matches. """ searchText, regExpObj, typeName, fieldName = self.findParameters() replaceText = self.replaceEntry.text() control = globalref.mainControl.activeControl qty = control.replaceAll(searchText, regExpObj, typeName, fieldName, replaceText) self.matchedSpot = None self.updateAvail() self.resultLabel.setText(_('Replaced {0} matches').format(qty)) def closeEvent(self, event): """Signal that the dialog is closing. Arguments: event -- the close event """ self.dialogShown.emit(False) def reject(self): """Handle use of escape key to close this dialog. """ self.close() SortWhat = enum.IntEnum('SortWhat', 'fullTree selectBranch selectChildren selectSiblings') SortMethod = enum.IntEnum('SortMethod', 'fieldSort titleSort') SortDirection = enum.IntEnum('SortDirection', 'forward reverse') class SortDialog(QDialog): """Dialog for defining sort operations. """ dialogShown = pyqtSignal(bool) def __init__(self, parent=None): """Initialize the sort dialog. Arguments: parent -- the parent window """ super().__init__(parent) self.setAttribute(Qt.WidgetAttribute.WA_QuitOnClose, False) self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowStaysOnTopHint) self.setWindowTitle(_('Sort Nodes')) topLayout = QVBoxLayout(self) self.setLayout(topLayout) horizLayout = QHBoxLayout() topLayout.addLayout(horizLayout) whatBox = QGroupBox(_('What to Sort')) horizLayout.addWidget(whatBox) whatLayout = QVBoxLayout(whatBox) self.whatButtons = QButtonGroup(self) button = QRadioButton(_('&Entire tree')) self.whatButtons.addButton(button, SortWhat.fullTree) whatLayout.addWidget(button) button = QRadioButton(_('Selected &branches')) self.whatButtons.addButton(button, SortWhat.selectBranch) whatLayout.addWidget(button) button = QRadioButton(_('Selection\'s childre&n')) self.whatButtons.addButton(button, SortWhat.selectChildren) whatLayout.addWidget(button) button = QRadioButton(_('Selection\'s &siblings')) self.whatButtons.addButton(button, SortWhat.selectSiblings) whatLayout.addWidget(button) self.whatButtons.button(SortWhat.fullTree).setChecked(True) vertLayout = QVBoxLayout() horizLayout.addLayout(vertLayout) methodBox = QGroupBox(_('Sort Method')) vertLayout.addWidget(methodBox) methodLayout = QVBoxLayout(methodBox) self.methodButtons = QButtonGroup(self) button = QRadioButton(_('&Predefined Key Fields')) self.methodButtons.addButton(button, SortMethod.fieldSort) methodLayout.addWidget(button) button = QRadioButton(_('Node &Titles')) self.methodButtons.addButton(button, SortMethod.titleSort) methodLayout.addWidget(button) self.methodButtons.button(SortMethod.fieldSort).setChecked(True) directionBox = QGroupBox(_('Sort Direction')) vertLayout.addWidget(directionBox) directionLayout = QVBoxLayout(directionBox) self.directionButtons = QButtonGroup(self) button = QRadioButton(_('&Forward')) self.directionButtons.addButton(button, SortDirection.forward) directionLayout.addWidget(button) button = QRadioButton(_('&Reverse')) self.directionButtons.addButton(button, SortDirection.reverse) directionLayout.addWidget(button) self.directionButtons.button(SortDirection.forward).setChecked(True) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.sortAndClose) applyButton = QPushButton(_('&Apply')) ctrlLayout.addWidget(applyButton) applyButton.clicked.connect(self.sortNodes) closeButton = QPushButton(_('&Close')) ctrlLayout.addWidget(closeButton) closeButton.clicked.connect(self.close) self.updateCommandsAvail() def updateCommandsAvail(self): """Set what to sort options available based on tree selections. """ selModel = globalref.mainControl.activeControl.currentSelectionModel() hasChild = False hasSibling = False for spot in selModel.selectedSpots(): if spot.nodeRef.childList: hasChild = True if spot.parentSpot and len(spot.parentSpot.nodeRef.childList) > 1: hasSibling = True self.whatButtons.button(SortWhat.selectBranch).setEnabled(hasChild) self.whatButtons.button(SortWhat.selectChildren).setEnabled(hasChild) self.whatButtons.button(SortWhat.selectSiblings).setEnabled(hasSibling) if not self.whatButtons.checkedButton().isEnabled(): self.whatButtons.button(SortWhat.fullTree).setChecked(True) def sortNodes(self): """Perform the sorting operation. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) control = globalref.mainControl.activeControl selSpots = control.currentSelectionModel().selectedSpots() if self.whatButtons.checkedId() == SortWhat.fullTree: selSpots = [control.structure.spotByNumber(0)] elif self.whatButtons.checkedId() == SortWhat.selectSiblings: selSpots = [spot.parentSpot for spot in selSpots] if self.whatButtons.checkedId() in (SortWhat.fullTree, SortWhat.selectBranch): rootSpots = selSpots[:] selSpots = [] for root in rootSpots: for spot in root.spotDescendantGen(): if spot.nodeRef.childList: selSpots.append(spot) undo.ChildListUndo(control.structure.undoList, [spot.nodeRef for spot in selSpots]) forward = self.directionButtons.checkedId() == SortDirection.forward if self.methodButtons.checkedId() == SortMethod.fieldSort: for spot in selSpots: spot.nodeRef.sortChildrenByField(False, forward) # reset temporary sort field storage for nodeFormat in control.structure.treeFormats.values(): nodeFormat.sortFields = [] else: for spot in selSpots: spot.nodeRef.sortChildrenByTitle(False, forward) control.updateAll() QApplication.restoreOverrideCursor() def sortAndClose(self): """Perform the sorting operation and close the dialog. """ self.sortNodes() self.close() def closeEvent(self, event): """Signal that the dialog is closing. Arguments: event -- the close event """ self.dialogShown.emit(False) def reject(self): """Handle use of escape key to close this dialog. """ self.close() NumberingScope = enum.IntEnum('NumberingScope', 'fullTree selectBranch selectChildren') NumberingNoField = enum.IntEnum('NumberingNoField', 'ignoreNoField restartAfterNoField reserveNoField') class NumberingDialog(QDialog): """Dialog for updating node nuumbering fields. """ dialogShown = pyqtSignal(bool) def __init__(self, parent=None): """Initialize the numbering dialog. Arguments: parent -- the parent window """ super().__init__(parent) self.setAttribute(Qt.WidgetAttribute.WA_QuitOnClose, False) self.setWindowFlags(Qt.WindowType.Window | Qt.WindowType.WindowStaysOnTopHint) self.setWindowTitle(_('Update Node Numbering')) topLayout = QVBoxLayout(self) self.setLayout(topLayout) whatBox = QGroupBox(_('What to Update')) topLayout.addWidget(whatBox) whatLayout = QVBoxLayout(whatBox) self.whatButtons = QButtonGroup(self) button = QRadioButton(_('&Entire tree')) self.whatButtons.addButton(button, NumberingScope.fullTree) whatLayout.addWidget(button) button = QRadioButton(_('Selected &branches')) self.whatButtons.addButton(button, NumberingScope.selectBranch) whatLayout.addWidget(button) button = QRadioButton(_('&Selection\'s children')) self.whatButtons.addButton(button, NumberingScope.selectChildren) whatLayout.addWidget(button) self.whatButtons.button(NumberingScope.fullTree).setChecked(True) rootBox = QGroupBox(_('Root Node')) topLayout.addWidget(rootBox) rootLayout = QVBoxLayout(rootBox) self.rootCheck = QCheckBox(_('Include top-level nodes')) rootLayout.addWidget(self.rootCheck) self.rootCheck.setChecked(True) noFieldBox = QGroupBox(_('Handling Nodes without Numbering ' 'Fields')) topLayout.addWidget(noFieldBox) noFieldLayout = QVBoxLayout(noFieldBox) self.noFieldButtons = QButtonGroup(self) button = QRadioButton(_('&Ignore and skip')) self.noFieldButtons.addButton(button, NumberingNoField.ignoreNoField) noFieldLayout.addWidget(button) button = QRadioButton(_('&Restart numbers for next siblings')) self.noFieldButtons.addButton(button, NumberingNoField.restartAfterNoField) noFieldLayout.addWidget(button) button = QRadioButton(_('Reserve &numbers')) self.noFieldButtons.addButton(button, NumberingNoField.reserveNoField) noFieldLayout.addWidget(button) self.noFieldButtons.button(NumberingNoField. ignoreNoField).setChecked(True) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.numberAndClose) applyButton = QPushButton(_('&Apply')) ctrlLayout.addWidget(applyButton) applyButton.clicked.connect(self.updateNumbering) closeButton = QPushButton(_('&Close')) ctrlLayout.addWidget(closeButton) closeButton.clicked.connect(self.close) self.updateCommandsAvail() def updateCommandsAvail(self): """Set branch numbering available based on tree selections. """ selNodes = globalref.mainControl.activeControl.currentSelectionModel() hasChild = False for node in selNodes.selectedNodes(): if node.childList: hasChild = True self.whatButtons.button(NumberingScope. selectChildren).setEnabled(hasChild) if not self.whatButtons.checkedButton().isEnabled(): self.whatButtons.button(NumberingScope.fullTree).setChecked(True) def checkForNumberingFields(self): """Check that the tree formats have numbering formats. Return a dict of numbering field names by node format name. If not found, warn user. """ fieldDict = (globalref.mainControl.activeControl.structure.treeFormats. numberingFieldDict()) if not fieldDict: QMessageBox.warning(self, _('TreeLine Numbering'), _('No numbering fields were found in data types')) return fieldDict def updateNumbering(self): """Perform the numbering update operation. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) fieldDict = self.checkForNumberingFields() if fieldDict: control = globalref.mainControl.activeControl selNodes = control.currentSelectionModel().selectedNodes() if (self.whatButtons.checkedId() == NumberingScope.fullTree or len(selNodes) == 0): selNodes = control.structure.childList undo.DataUndo(control.structure.undoList, selNodes, addBranch=True) reserveNums = (self.noFieldButtons.checkedId() == NumberingNoField.reserveNoField) restartSetting = (self.noFieldButtons.checkedId() == NumberingNoField.restartAfterNoField) includeRoot = self.rootCheck.isChecked() if self.whatButtons.checkedId() == NumberingScope.selectChildren: levelLimit = 2 else: levelLimit = sys.maxsize startNum = [1] completedClones = set() for node in selNodes: node.updateNumbering(fieldDict, startNum, levelLimit, completedClones, includeRoot, reserveNums, restartSetting) control.updateAll() QApplication.restoreOverrideCursor() def numberAndClose(self): """Perform the numbering update operation and close the dialog. """ self.updateNumbering() self.close() def closeEvent(self, event): """Signal that the dialog is closing. Arguments: event -- the close event """ self.dialogShown.emit(False) def reject(self): """Handle use of escape key to close this dialog. """ self.close() menuNames = collections.OrderedDict([(N_('File Menu'), _('File')), (N_('Edit Menu'), _('Edit')), (N_('Node Menu'), _('Node')), (N_('Data Menu'), _('Data')), (N_('Tools Menu'), _('Tools')), (N_('Format Menu'), _('Format')), (N_('View Menu'), _('View')), (N_('Window Menu'), _('Window')), (N_('Help Menu'), _('Help'))]) class CustomShortcutsDialog(QDialog): """Dialog for customizing keyboard commands. """ def __init__(self, allActions, parent=None): """Create a shortcuts selection dialog. Arguments: allActions -- dict of all actions from a window parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Keyboard Shortcuts')) topLayout = QVBoxLayout(self) self.setLayout(topLayout) scrollArea = QScrollArea() topLayout.addWidget(scrollArea) viewport = QWidget() viewLayout = QGridLayout(viewport) scrollArea.setWidget(viewport) scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) scrollArea.setWidgetResizable(True) self.editors = [] for i, keyOption in enumerate(globalref.keyboardOptions.values()): category = menuNames.get(keyOption.category, _('No menu')) try: action = allActions[keyOption.name] except KeyError: pass else: text = '{0} > {1}'.format(category, action.toolTip()) label = QLabel(text) viewLayout.addWidget(label, i, 0) editor = KeyLineEdit(keyOption, action, self) viewLayout.addWidget(editor, i, 1) self.editors.append(editor) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) restoreButton = QPushButton(_('&Restore Defaults')) ctrlLayout.addWidget(restoreButton) restoreButton.clicked.connect(self.restoreDefaults) ctrlLayout.addStretch(0) self.okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(self.okButton) self.okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.editors[0].setFocus() def restoreDefaults(self): """Restore all default keyboard shortcuts. """ for editor in self.editors: editor.loadDefaultKey() def accept(self): """Save any changes to options and actions before closing. """ modified = False for editor in self.editors: if editor.modified: editor.saveChange() modified = True if modified: globalref.keyboardOptions.writeFile() super().accept() class KeyLineEdit(QLineEdit): """Line editor for keyboad sequence entry. """ usedKeySet = set() blankText = ' ' * 8 def __init__(self, keyOption, action, parent=None): """Create a key editor. Arguments: keyOption -- the KeyOptionItem for this editor action -- the action to update on changes parent -- the parent dialog """ super().__init__(parent) self.keyOption = keyOption self.keyAction = action self.key = None self.modified = False self.setReadOnly(True) self.loadKey() def loadKey(self): """Load the initial key shortcut from the option. """ key = self.keyOption.value if key: self.setKey(key) else: self.setText(KeyLineEdit.blankText) def loadDefaultKey(self): """Change to the default key shortcut from the option. Arguments: useDefault -- if True, load the default key """ key = self.keyOption.defaultValue if key == self.key: return if key: self.setKey(key) self.modified = True else: self.clearKey(False) def setKey(self, key): """Set this editor to the given key and add to the used key set. Arguments: key - the QKeySequence to add """ keyText = key.toString(QKeySequence.SequenceFormat.NativeText) self.setText(keyText) self.key = key KeyLineEdit.usedKeySet.add(keyText) def clearKey(self, staySelected=True): """Remove any existing key. """ self.setText(KeyLineEdit.blankText) if staySelected: self.selectAll() if self.key: KeyLineEdit.usedKeySet.remove(self.key.toString(QKeySequence. SequenceFormat. NativeText)) self.key = None self.modified = True def saveChange(self): """Save any change to the option and action. """ if self.modified: self.keyOption.setValue(self.key) if self.key: self.keyAction.setShortcut(self.key) else: self.keyAction.setShortcut(QKeySequence()) def keyPressEvent(self, event): """Capture key strokes and update the editor if valid. Arguments: event -- the key press event """ if event.key() in (Qt.Key.Key_Shift, Qt.Key.Key_Control, Qt.Key.Key_Meta, Qt.Key.Key_Alt, Qt.Key.Key_AltGr, Qt.Key.Key_CapsLock, Qt.Key.Key_NumLock, Qt.Key.Key_ScrollLock, Qt.Key.Key_Pause, Qt.Key.Key_Print, Qt.Key.Key_Cancel): event.ignore() elif event.key() in (Qt.Key.Key_Backspace, Qt.Key.Key_Escape): self.clearKey() event.accept() else: key = QKeySequence(event.keyCombination()) if key != self.key: keyText = key.toString(QKeySequence.SequenceFormat.NativeText) if keyText not in KeyLineEdit.usedKeySet: if self.key: KeyLineEdit.usedKeySet.remove(self.key. toString(QKeySequence. SequenceFormat. NativeText)) self.setKey(key) self.selectAll() self.modified = True else: text = _('Key {0} is already used').format(keyText) QMessageBox.warning(self.parent(), 'TreeLine', text) event.accept() def contextMenuEvent(self, event): """Change to a context menu with a clear command. Arguments: event -- the menu event """ menu = QMenu(self) menu.addAction(_('Clear &Key'), self.clearKey) menu.exec(event.globalPos()) def mousePressEvent(self, event): """Capture mouse clicks to avoid selection loss. Arguments: event -- the mouse event """ event.accept() def mouseReleaseEvent(self, event): """Capture mouse clicks to avoid selection loss. Arguments: event -- the mouse event """ event.accept() def mouseMoveEvent(self, event): """Capture mouse clicks to avoid selection loss. Arguments: event -- the mouse event """ event.accept() def mouseDoubleClickEvent(self, event): """Capture mouse clicks to avoid selection loss. Arguments: event -- the mouse event """ event.accept() def focusInEvent(self, event): """Select contents when focussed. Arguments: event -- the focus event """ self.selectAll() super().focusInEvent(event) class CustomToolbarDialog(QDialog): """Dialog for customizing toolbar buttons. """ separatorString = _('--Separator--') def __init__(self, allActions, updateFunction, parent=None): """Create a toolbar buttons customization dialog. Arguments: allActions -- dict of all actions from a window updateFunction -- a function ref for updating window toolbars parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Customize Toolbars')) self.allActions = allActions self.updateFunction = updateFunction self.availableCommands = [] self.modified = False self.numToolbars = 0 self.availableCommands = [] self.toolbarLists = [] topLayout = QVBoxLayout(self) self.setLayout(topLayout) gridLayout = QGridLayout() topLayout.addLayout(gridLayout) sizeBox = QGroupBox(_('Toolbar &Size')) gridLayout.addWidget(sizeBox, 0, 0, 1, 2) sizeLayout = QVBoxLayout(sizeBox) self.sizeCombo = QComboBox() sizeLayout.addWidget(self.sizeCombo) self.sizeCombo.addItems([_('Small Icons'), _('Large Icons')]) self.sizeCombo.currentIndexChanged.connect(self.setModified) numberBox = QGroupBox(_('Toolbar Quantity')) gridLayout.addWidget(numberBox, 0, 2) numberLayout = QHBoxLayout(numberBox) self.quantitySpin = QSpinBox() numberLayout.addWidget(self.quantitySpin) self.quantitySpin.setRange(0, 20) numberlabel = QLabel(_('&Toolbars')) numberLayout.addWidget(numberlabel) numberlabel.setBuddy(self.quantitySpin) self.quantitySpin.valueChanged.connect(self.changeQuantity) availableBox = QGroupBox(_('A&vailable Commands')) gridLayout.addWidget(availableBox, 1, 0) availableLayout = QVBoxLayout(availableBox) menuCombo = QComboBox() availableLayout.addWidget(menuCombo) menuCombo.addItems([_(name) for name in menuNames.keys()]) menuCombo.currentIndexChanged.connect(self.updateAvailableCommands) self.availableListWidget = QListWidget() availableLayout.addWidget(self.availableListWidget) buttonLayout = QVBoxLayout() gridLayout.addLayout(buttonLayout, 1, 1) self.addButton = QPushButton('>>') buttonLayout.addWidget(self.addButton) self.addButton.setMaximumWidth(self.addButton.sizeHint().height()) self.addButton.clicked.connect(self.addTool) self.removeButton = QPushButton('<<') buttonLayout.addWidget(self.removeButton) self.removeButton.setMaximumWidth(self.removeButton.sizeHint(). height()) self.removeButton.clicked.connect(self.removeTool) toolbarBox = QGroupBox(_('Tool&bar Commands')) gridLayout.addWidget(toolbarBox, 1, 2) toolbarLayout = QVBoxLayout(toolbarBox) self.toolbarCombo = QComboBox() toolbarLayout.addWidget(self.toolbarCombo) self.toolbarCombo.currentIndexChanged.connect(self. updateToolbarCommands) self.toolbarListWidget = QListWidget() toolbarLayout.addWidget(self.toolbarListWidget) self.toolbarListWidget.currentRowChanged.connect(self. setButtonsAvailable) moveLayout = QHBoxLayout() toolbarLayout.addLayout(moveLayout) self.moveUpButton = QPushButton(_('Move &Up')) moveLayout.addWidget(self.moveUpButton) self.moveUpButton.clicked.connect(self.moveUp) self.moveDownButton = QPushButton(_('Move &Down')) moveLayout.addWidget(self.moveDownButton) self.moveDownButton.clicked.connect(self.moveDown) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) restoreButton = QPushButton(_('&Restore Defaults')) ctrlLayout.addWidget(restoreButton) restoreButton.clicked.connect(self.restoreDefaults) ctrlLayout.addStretch() self.okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(self.okButton) self.okButton.clicked.connect(self.accept) self.applyButton = QPushButton(_('&Apply')) ctrlLayout.addWidget(self.applyButton) self.applyButton.clicked.connect(self.applyChanges) self.applyButton.setEnabled(False) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.updateAvailableCommands(0) self.loadToolbars() def setModified(self): """Set modified flag and make apply button available. """ self.modified = True self.applyButton.setEnabled(True) def setButtonsAvailable(self): """Enable or disable buttons based on toolbar list state. """ toolbarNum = numCommands = commandNum = 0 if self.numToolbars: toolbarNum = self.toolbarCombo.currentIndex() numCommands = len(self.toolbarLists[toolbarNum]) if self.toolbarLists[toolbarNum]: commandNum = self.toolbarListWidget.currentRow() self.addButton.setEnabled(self.numToolbars > 0) self.removeButton.setEnabled(self.numToolbars and numCommands) self.moveUpButton.setEnabled(self.numToolbars and numCommands > 1 and commandNum > 0) self.moveDownButton.setEnabled(self.numToolbars and numCommands > 1 and commandNum < numCommands - 1) def loadToolbars(self, defaultOnly=False): """Load all toolbar data from options. Arguments: defaultOnly -- if True, load default settings """ size = (globalref.toolbarOptions['ToolbarSize'] if not defaultOnly else globalref.toolbarOptions.getDefaultValue('ToolbarSize')) self.sizeCombo.blockSignals(True) if size < 24: self.sizeCombo.setCurrentIndex(0) else: self.sizeCombo.setCurrentIndex(1) self.sizeCombo.blockSignals(False) self.numToolbars = (globalref.toolbarOptions['ToolbarQuantity'] if not defaultOnly else globalref.toolbarOptions. getDefaultValue('ToolbarQuantity')) self.quantitySpin.blockSignals(True) self.quantitySpin.setValue(self.numToolbars) self.quantitySpin.blockSignals(False) self.toolbarLists = [] commands = (globalref.toolbarOptions['ToolbarCommands'] if not defaultOnly else globalref.toolbarOptions. getDefaultValue('ToolbarCommands')) self.toolbarLists = [cmd.split(',') for cmd in commands] # account for toolbar quantity mismatch (should not happen) del self.toolbarLists[self.numToolbars:] while len(self.toolbarLists) < self.numToolbars: self.toolbarLists.append([]) self.updateToolbarCombo() def updateToolbarCombo(self): """Fill combo with toolbar numbers for current quantity. """ self.toolbarCombo.clear() if self.numToolbars: self.toolbarCombo.addItems(['Toolbar {0}'.format(num + 1) for num in range(self.numToolbars)]) else: self.toolbarListWidget.clear() self.setButtonsAvailable() def updateAvailableCommands(self, menuNum): """Fill in available command list for given menu. Arguments: menuNum -- the index of the current menu selected """ menuName = list(menuNames.keys())[menuNum] self.availableCommands = [] self.availableListWidget.clear() for option in globalref.keyboardOptions.values(): if option.category == menuName: action = self.allActions[option.name] icon = action.icon() if not icon.isNull(): self.availableCommands.append(option.name) QListWidgetItem(icon, action.toolTip(), self.availableListWidget) QListWidgetItem(CustomToolbarDialog.separatorString, self.availableListWidget) self.availableListWidget.setCurrentRow(0) def updateToolbarCommands(self, toolbarNum): """Fill in toolbar commands for given toolbar. Arguments: toolbarNum -- the number of the toolbar to update """ self.toolbarListWidget.clear() if self.numToolbars == 0: return for command in self.toolbarLists[toolbarNum]: if command: action = self.allActions[command] QListWidgetItem(action.icon(), action.toolTip(), self.toolbarListWidget) else: # separator QListWidgetItem(CustomToolbarDialog.separatorString, self.toolbarListWidget) if self.toolbarLists[toolbarNum]: self.toolbarListWidget.setCurrentRow(0) self.setButtonsAvailable() def changeQuantity(self, qty): """Change the toolbar quantity based on a spin box signal. Arguments: qty -- the new toolbar quantity """ self.numToolbars = qty while qty > len(self.toolbarLists): self.toolbarLists.append([]) self.updateToolbarCombo() self.setModified() def addTool(self): """Add the selected command to the current toolbar. """ toolbarNum = self.toolbarCombo.currentIndex() try: command = self.availableCommands[self.availableListWidget. currentRow()] action = self.allActions[command] item = QListWidgetItem(action.icon(), action.toolTip()) except IndexError: command = '' item = QListWidgetItem(CustomToolbarDialog.separatorString) if self.toolbarLists[toolbarNum]: pos = self.toolbarListWidget.currentRow() + 1 else: pos = 0 self.toolbarLists[toolbarNum].insert(pos, command) self.toolbarListWidget.insertItem(pos, item) self.toolbarListWidget.setCurrentRow(pos) self.toolbarListWidget.scrollToItem(item) self.setModified() def removeTool(self): """Remove the selected command from the current toolbar. """ toolbarNum = self.toolbarCombo.currentIndex() pos = self.toolbarListWidget.currentRow() del self.toolbarLists[toolbarNum][pos] self.toolbarListWidget.takeItem(pos) if self.toolbarLists[toolbarNum]: if pos == len(self.toolbarLists[toolbarNum]): pos -= 1 self.toolbarListWidget.setCurrentRow(pos) self.setModified() def moveUp(self): """Raise the selected command. """ toolbarNum = self.toolbarCombo.currentIndex() pos = self.toolbarListWidget.currentRow() command = self.toolbarLists[toolbarNum].pop(pos) self.toolbarLists[toolbarNum].insert(pos - 1, command) item = self.toolbarListWidget.takeItem(pos) self.toolbarListWidget.insertItem(pos - 1, item) self.toolbarListWidget.setCurrentRow(pos - 1) self.toolbarListWidget.scrollToItem(item) self.setModified() def moveDown(self): """Lower the selected command. """ toolbarNum = self.toolbarCombo.currentIndex() pos = self.toolbarListWidget.currentRow() command = self.toolbarLists[toolbarNum].pop(pos) self.toolbarLists[toolbarNum].insert(pos + 1, command) item = self.toolbarListWidget.takeItem(pos) self.toolbarListWidget.insertItem(pos + 1, item) self.toolbarListWidget.setCurrentRow(pos + 1) self.toolbarListWidget.scrollToItem(item) self.setModified() def restoreDefaults(self): """Restore all default toolbar settings. """ self.loadToolbars(True) self.setModified() def applyChanges(self): """Apply any changes from the dialog. """ size = 16 if self.sizeCombo.currentIndex() == 0 else 32 globalref.toolbarOptions.changeValue('ToolbarSize', size) globalref.toolbarOptions.changeValue('ToolbarQuantity', self.numToolbars) del self.toolbarLists[self.numToolbars:] commands = [','.join(cmds) for cmds in self.toolbarLists] globalref.toolbarOptions.changeValue('ToolbarCommands', commands) globalref.toolbarOptions.writeFile() self.modified = False self.applyButton.setEnabled(False) self.updateFunction() def accept(self): """Apply changes and close the dialog. """ if self.modified: self.applyChanges() super().accept() class CustomFontData: """Class to store custom font settings. Acts as a stand-in for PrintData class in the font page of the dialog. """ def __init__(self, fontOption, useAppDefault=True): """Initialize the font data. Arguments: fontOption -- the name of the font setting to retrieve useAppDefault -- use app default if true, o/w use sys default """ self.fontOption = fontOption if useAppDefault: self.defaultFont = QTextDocument().defaultFont() else: self.defaultFont = QFont(globalref.mainControl.systemFont) self.useDefaultFont = True self.mainFont = QFont(self.defaultFont) fontName = globalref.miscOptions[self.fontOption] if fontName: self.mainFont.fromString(fontName) self.useDefaultFont = False def recordChanges(self): """Record the updated font info to the option settings. """ if self.useDefaultFont: globalref.miscOptions.changeValue(self.fontOption, '') else: globalref.miscOptions.changeValue(self.fontOption, self.mainFont.toString()) class CustomFontDialog(QDialog): """Dialog for selecting custom fonts. Uses the print setup dialog's font page for the details. """ updateRequired = pyqtSignal() def __init__(self, parent=None): """Create a font customization dialog. Arguments: parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Customize Fonts')) topLayout = QVBoxLayout(self) self.setLayout(topLayout) self.tabs = QTabWidget() topLayout.addWidget(self.tabs) self.tabs.setUsesScrollButtons(False) self.tabs.currentChanged.connect(self.updateTabDefault) self.pages = [] defaultLabel = _('&Use system default font') appFontPage = printdialogs.FontPage(CustomFontData('AppFont', False), defaultLabel) self.pages.append(appFontPage) self.tabs.addTab(appFontPage, _('App Default Font')) defaultLabel = _('&Use app default font') treeFontPage = printdialogs.FontPage(CustomFontData('TreeFont'), defaultLabel) self.pages.append(treeFontPage) self.tabs.addTab(treeFontPage, _('Tree View Font')) outputFontPage = printdialogs.FontPage(CustomFontData('OutputFont'), defaultLabel) self.pages.append(outputFontPage) self.tabs.addTab(outputFontPage, _('Output View Font')) editorFontPage = printdialogs.FontPage(CustomFontData('EditorFont'), defaultLabel) self.pages.append(editorFontPage) self.tabs.addTab(editorFontPage, _('Editor View Font')) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() self.okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(self.okButton) self.okButton.clicked.connect(self.accept) self.applyButton = QPushButton(_('&Apply')) ctrlLayout.addWidget(self.applyButton) self.applyButton.clicked.connect(self.applyChanges) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) def updateTabDefault(self): """Update the default font on the newly shown page. """ appFontWidget = self.tabs.widget(0) currentWidget = self.tabs.currentWidget() if appFontWidget is not currentWidget: if appFontWidget.defaultCheck.isChecked(): defaultFont = QFont(globalref.mainControl.systemFont) else: defaultFont = appFontWidget.readFont() if defaultFont: currentWidget.printData.defaultFont = defaultFont if currentWidget.defaultCheck.isChecked(): currentWidget.printData.mainFont = QFont(defaultFont) currentWidget.currentFont = (currentWidget.printData. mainFont) currentWidget.setFont(defaultFont) def applyChanges(self): """Apply any changes from the dialog. """ modified = False for page in self.pages: if page.saveChanges(): page.printData.recordChanges() modified = True if modified: globalref.miscOptions.writeFile() self.updateRequired.emit() def accept(self): """Apply changes and close the dialog. """ self.applyChanges() super().accept() class AboutDialog(QDialog): """Show program info in a text box. """ def __init__(self, title, textLines, icon=None, parent=None): """Create the dialog. Arguments: title -- the window title text textLines -- a list of lines to show icon -- an icon to show if given parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(title) topLayout = QVBoxLayout(self) self.setLayout(topLayout) mainLayout = QHBoxLayout() topLayout.addLayout(mainLayout) iconLabel = QLabel() iconLabel.setPixmap(icon.pixmap(128, 128)) mainLayout.addWidget(iconLabel) textBox = QPlainTextEdit() textBox.setReadOnly(True) textBox.setWordWrapMode(QTextOption.WrapMode.NoWrap) textBox.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) textBox.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) text = '\n'.join(textLines) textBox.setPlainText(text) size = textBox.fontMetrics().size(0, text) size.setHeight(size.height() + 10) size.setWidth(size.width() + 10) textBox.setMinimumSize(size) mainLayout.addWidget(textBox) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) TreeLine-3.2.1/source/nodeformat.py000066400000000000000000000606551506556630100172570ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # nodeformat.py, provides a class to handle node format objects # # TreeLine, an information storage program # Copyright (C) 2023, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import collections import os.path import sys import copy import operator import datetime import xml.sax.saxutils if not sys.platform.startswith('win'): import pwd import fieldformat import conditional defaultFieldName = _('Name') _defaultOutputSeparator = ', ' _fieldSplitRe = re.compile(r'({\*(?:\**|\?|!|&|#)[\w_\-.]+\*})') _fieldPartRe = re.compile(r'{\*(\**|\?|!|&|#)([\w_\-.]+)\*}') _endTagRe = re.compile(r'.*(|||)$') _levelFieldRe = re.compile(r'[^0-9]+([0-9]+)$') class NodeFormat: """Class to handle node format info Stores node field lists and line formatting. Provides methods to return formatted data. """ def __init__(self, name, parentFormats, formatData=None, addDefaultField=False): """Initialize a tree format. Arguments: name -- the type name string parentFormats -- a ref to TreeFormats class for outside field refs formatData -- the JSON dict for this format addDefaultField -- if true, adds a default initial field """ self.name = name self.parentFormats = parentFormats self.savedConditionText = {} self.conditional = None self.childTypeLimit = set() self.readFormat(formatData) self.siblingPrefix = '' self.siblingSuffix = '' self.derivedTypes = [] self.origOutputLines = [] # lines without bullet or table modifications self.sortFields = [] # temporary storage while sorting if addDefaultField: self.addFieldIfNew(defaultFieldName) self.titleLine = ['{{*{0}*}}'.format(defaultFieldName)] self.outputLines = [['{{*{0}*}}'.format(defaultFieldName)]] self.updateLineParsing() if self.useBullets: self.addBullets() if self.useTables: self.addTables() def readFormat(self, formatData=None): """Read JSON format data into this format. Arguments: formatData -- JSON dict for this format (None for default settings) """ self.fieldDict = collections.OrderedDict() if formatData: for fieldData in formatData.get('fields', []): fieldName = fieldData['fieldname'] self.addField(fieldName, fieldData) else: formatData = {} self.titleLine = [formatData.get('titleline', '')] self.outputLines = [[line] for line in formatData.get('outputlines', [])] self.spaceBetween = formatData.get('spacebetween', True) self.formatHtml = formatData.get('formathtml', False) self.useBullets = formatData.get('bullets', False) self.useTables = formatData.get('tables', False) self.childType = formatData.get('childtype', '') self.genericType = formatData.get('generic', '') if 'condition' in formatData: self.conditional = conditional.Conditional(formatData['condition']) if 'childTypeLimit' in formatData: self.childTypeLimit = set(formatData['childTypeLimit']) else: self.childTypeLimit = set() self.iconName = formatData.get('icon', '') self.outputSeparator = formatData.get('outputsep', _defaultOutputSeparator) for key in formatData.keys(): if key.startswith('cond-'): self.savedConditionText[key[5:]] = formatData[key] def storeFormat(self): """Return JSON format data for this format. """ formatData = {} formatData['formatname'] = self.name formatData['fields'] = [field.formatData() for field in self.fields()] formatData['titleline'] = self.getTitleLine() formatData['outputlines'] = self.getOutputLines() if not self.spaceBetween: formatData['spacebetween'] = False if self.formatHtml: formatData['formathtml'] = True if self.useBullets: formatData['bullets'] = True if self.useTables: formatData['tables'] = True if self.childType: formatData['childtype'] = self.childType if self.genericType: formatData['generic'] = self.genericType if self.conditional: formatData['condition'] = self.conditional.conditionStr() if self.childTypeLimit: formatData['childTypeLimit'] = sorted(list(self.childTypeLimit)) if self.iconName: formatData['icon'] = self.iconName if self.outputSeparator != _defaultOutputSeparator: formatData['outputsep'] = self.outputSeparator for key, text in self.savedConditionText.items(): formatData['cond-' + key] = text return formatData def copySettings(self, sourceFormat): """Copy all settings from another format to this one. Arguments: sourceFormat -- the format to copy """ self.name = sourceFormat.name self.readFormat(sourceFormat.storeFormat()) self.siblingPrefix = sourceFormat.siblingPrefix self.siblingSuffix = sourceFormat.siblingSuffix self.outputLines = sourceFormat.getOutputLines(False) self.origOutputLines = sourceFormat.getOutputLines() self.updateLineParsing() def fields(self): """Return list of all fields. """ return self.fieldDict.values() def fieldNames(self): """Return list of names of all fields. """ return list(self.fieldDict.keys()) def formatTitle(self, node, spotRef=None): """Return a string with formatted title data. Arguments: node -- the node used to get data for fields spotRef -- optional, used for ancestor field refs """ line = ''.join([part.outputText(node, True, True, self.formatHtml) if hasattr(part, 'outputText') else part for part in self.titleLine]) return line.strip() def formatOutput(self, node, plainText=False, keepBlanks=False, spotRef=None): """Return a list of formatted text output lines. Arguments: node -- the node used to get data for fields plainText -- if True, remove HTML markup from fields and formats keepBlanks -- if True, keep lines with empty fields spotRef -- optional, used for ancestor field refs """ result = [] for lineData in self.outputLines: line = '' numEmptyFields = 0 numFullFields = 0 for part in lineData: if hasattr(part, 'outputText'): text = part.outputText(node, False, plainText, self.formatHtml) if text: numFullFields += 1 else: numEmptyFields += 1 line += text else: if not self.formatHtml and not plainText: part = xml.sax.saxutils.escape(part) elif self.formatHtml and plainText: part = fieldformat.removeMarkup(part) line += part if keepBlanks or numFullFields or not numEmptyFields: result.append(line) elif self.formatHtml and not plainText and result: # add ending HTML tag from skipped line back to previous line endTagMatch = _endTagRe.match(line) if endTagMatch: result[-1] += endTagMatch.group(1) return result def addField(self, name, fieldData=None): """Add a field type with its format to the field list. Arguments: name -- the field name string fieldData -- the dict that defines this field's format """ if not fieldData: fieldData = {} typeName = '{}Field'.format(fieldData.get('fieldtype', 'Text')) fieldClass = getattr(fieldformat, typeName, fieldformat.TextField) field = fieldClass(name, fieldData) self.fieldDict[name] = field def addFieldIfNew(self, name, fieldData=None): """Add a field type to the field list if not already there. Arguments: name -- the field name string fieldData -- the dict that defines this field's format """ if name not in self.fieldDict: self.addField(name, fieldData) def addFieldList(self, nameList, addFirstTitle=False, addToOutput=False): """Add text fields with names given in list. Also add to title and output lines if addOutput is True. Arguments: nameList -- the list of names to add addFirstTitle -- if True, use first field for title output format addToOutput -- replace output lines with all fields if True """ for name in nameList: self.addFieldIfNew(name) if addFirstTitle: self.changeTitleLine('{{*{0}*}}'.format(nameList[0])) if addToOutput: self.changeOutputLines(['{{*{0}*}}'.format(name) for name in nameList]) def reorderFields(self, fieldNameList): """Change the order of fieldDict to match the given list. Arguments: fieldNameList -- a list of existing field names in a desired order """ newFieldDict = collections.OrderedDict() for fieldName in fieldNameList: newFieldDict[fieldName] = self.fieldDict[fieldName] self.fieldDict = newFieldDict def removeField(self, field): """Remove all occurances of field from title and output lines. Arguments: field -- the field to be removed """ while field in self.titleLine: self.titleLine.remove(field) for lineData in self.outputLines: while field in lineData: lineData.remove(field) self.outputLines = [line for line in self.outputLines if line] # if len(self.lineList) == 0: # self.lineList.append(['']) def setInitDefaultData(self, data, overwrite=False): """Add initial default data from fields into supplied data dict. Arguments: data -- the data dict to modify overwrite -- if true, replace previous data entries """ for field in self.fields(): text = field.getInitDefault() if text and (overwrite or not data.get(field.name, '')): data[field.name] = text def updateLineParsing(self): """Update the fields parsed in the output lines. Converts lines back to whole lines with embedded field names, then parse back to individual fields and text. """ self.titleLine = self.parseLine(self.getTitleLine()) self.outputLines = [self.parseLine(line) for line in self.getOutputLines(False)] if self.origOutputLines: self.origOutputLines = [self.parseLine(line) for line in self.getOutputLines(True)] def parseLine(self, text): """Parse text format line, return list of field types and text. Splits the line into field and text segments. Arguments: text -- the raw format text line to be parsed """ text = ' '.join(text.split()) segments = (part for part in _fieldSplitRe.split(text) if part) return [self.parseField(part) for part in segments] def parseField(self, text): """Parse text field, return field type or plain text if not a field. Arguments: text -- the raw format text (could be a field) """ fieldMatch = _fieldPartRe.match(text) if fieldMatch: modifier = fieldMatch.group(1) fieldName = fieldMatch.group(2) try: if not modifier: return self.fieldDict[fieldName] elif modifier == '*' * len(modifier): return fieldformat.AncestorLevelField(fieldName, len(modifier)) elif modifier == '?': return fieldformat.AnyAncestorField(fieldName) elif modifier == '&': return fieldformat.ChildListField(fieldName) elif modifier == '#': match = _levelFieldRe.match(fieldName) if match and match.group(1) != '0': level = int(match.group(1)) return fieldformat.DescendantCountField(fieldName, level) elif modifier == '!': return (self.parentFormats.fileInfoFormat. fieldDict[fieldName]) except KeyError: pass return text def getTitleLine(self): """Return text of title format with field names embedded. """ return ''.join([part.sepName() if hasattr(part, 'sepName') else part for part in self.titleLine]) def getOutputLines(self, useOriginal=True): """Return text list of output format lines with field names embedded. Arguments: useOriginal -- use original line list, wothout bullet or table mods """ lines = self.outputLines if useOriginal and self.origOutputLines: lines = self.origOutputLines lines = [''.join([part.sepName() if hasattr(part, 'sepName') else part for part in line]) for line in lines] return lines if lines else [''] def changeTitleLine(self, text): """Replace the title format line. Arguments: text -- the new title format line """ self.titleLine = self.parseLine(text) if not self.titleLine: self.titleLine = [''] def changeOutputLines(self, lines, keepBlanks=False): """Replace the output format lines with given list. Arguments: lines -- a list of replacement format lines keepBlanks -- if False, ignore blank lines """ self.outputLines = [] for line in lines: newLine = self.parseLine(line) if keepBlanks or newLine: self.outputLines.append(newLine) if self.useBullets: self.origOutputLines = self.outputLines[:] self.addBullets() if self.useTables: self.origOutputLines = self.outputLines[:] self.addTables() def addOutputLine(self, line): """Add an output format line after existing lines. Arguments: line -- the text line to add """ newLine = self.parseLine(line) if newLine: self.outputLines.append(newLine) def extractTitleData(self, titleString, data): """Modifies the data dictionary based on a title string. Match the title format to the string, return True if successful. Arguments: title -- the string with the new title data -- the data dictionary to be modified """ fields = [] pattern = '' extraText = '' for seg in self.titleLine: if hasattr(seg, 'name'): # a field segment fields.append(seg) pattern += '(.*)' else: # a text separator pattern += re.escape(seg) extraText += seg match = re.match(pattern, titleString) try: if match: for num, field in enumerate(fields): text = match.group(num + 1) data[field.name] = field.storedTextFromTitle(text) elif not extraText.strip(): # assign to 1st field if sep is only spaces text = fields[0].storedTextFromTitle(titleString) data[fields[0].name] = text for field in fields[1:]: data[field.name] = '' else: return False except ValueError: return False return True def updateDerivedTypes(self): """Update derived types after changes to this generic type. """ for derivedType in self.derivedTypes: derivedType.updateFromGeneric(self) def updateFromGeneric(self, genericType=None, formatsRef=None): """Update fields and field types to match a generic type. Does nothing if self is not a derived type. Must provide either the genericType or a formatsRef. Arguments: genericType -- the type to update from formatsRef -- the tree formats dict to update from """ if not self.genericType: return if not genericType: genericType = formatsRef[self.genericType] newFields = collections.OrderedDict() for field in genericType.fieldDict.values(): fieldMatch = self.fieldDict.get(field.name, None) if fieldMatch and field.typeName == fieldMatch.typeName: newFields[field.name] = fieldMatch else: newFields[field.name] = copy.deepcopy(field) self.fieldDict = newFields self.updateLineParsing() def addBullets(self): """Add bullet HTML tags to sibling prefix, suffix and output lines. """ self.siblingPrefix = '
      ' self.siblingSuffix = '
    ' lines = self.getOutputLines() if lines != ['']: lines[0] = '
  • ' + lines[0] lines[-1] += '
  • ' self.origOutputLines = self.outputLines[:] self.outputLines = lines self.updateLineParsing() def addTables(self): """Add table HTML tags to sibling prefix, suffix and output lines. """ lines = [line for line in self.getOutputLines() if line] newLines = [] headings = [] for line in lines: head = '' firstPart = self.parseLine(line)[0] if hasattr(firstPart, 'split') and ':' in firstPart: head, line = line.split(':', 1) newLines.append(line.strip()) headings.append(head.strip()) self.siblingPrefix = '' if [head for head in headings if head]: self.siblingPrefix += '' for head in headings: self.siblingPrefix = ('{0}'. format(self.siblingPrefix, head)) self.siblingPrefix += '' self.siblingSuffix = '
    {1}
    ' newLines = ['{0}'.format(line) for line in newLines] newLines[0] = '' + newLines[0] newLines[-1] += '' self.origOutputLines = self.outputLines[:] self.outputLines = newLines self.updateLineParsing() def clearBulletsAndTables(self): """Remove any HTML tags for bullets and tables. """ self.siblingPrefix = '' self.siblingSuffix = '' if self.origOutputLines: self.outputLines = self.origOutputLines self.updateLineParsing() self.origOutputLines = [] def numberingFieldList(self): """Return a list of numbering field names. """ return [field.name for field in self.fieldDict.values() if field.typeName == 'Numbering'] def loadSortFields(self): """Add sort fields to temporarily stored list. Only used for efficiency while sorting. """ self.sortFields = [field for field in self.fields() if field.sortKeyNum > 0] self.sortFields.sort(key = operator.attrgetter('sortKeyNum')) if not self.sortFields: self.sortFields = [list(self.fields())[0]] class FileInfoFormat(NodeFormat): """Node format class to store and update special file info fields. Fields used in print header/footer and in outputs of other node types. """ typeName = 'INT_TL_FILE_DATA_FORM' fileFieldName = 'File_Name' pathFieldName = 'File_Path' sizeFieldName = 'File_Size' dateFieldName = 'File_Mod_Date' timeFieldName = 'File_Mod_Time' ownerFieldName = 'File_Owner' pageNumFieldName = 'Page_Number' numPagesFieldName = 'Number_of_Pages' def __init__(self, parentFormats): """Create a file info format. """ super().__init__(FileInfoFormat.typeName, parentFormats) self.fieldFormatModified = False self.addField(FileInfoFormat.fileFieldName) self.addField(FileInfoFormat.pathFieldName) self.addField(FileInfoFormat.sizeFieldName, {'fieldtype': 'Number'}) self.addField(FileInfoFormat.dateFieldName, {'fieldtype': 'Date'}) self.addField(FileInfoFormat.timeFieldName, {'fieldtype': 'Time'}) if not sys.platform.startswith('win'): self.addField(FileInfoFormat.ownerFieldName) # page info only for print header: self.addField(FileInfoFormat.pageNumFieldName) self.fieldDict[FileInfoFormat.pageNumFieldName].showInDialog = False self.addField(FileInfoFormat.numPagesFieldName) self.fieldDict[FileInfoFormat.numPagesFieldName].showInDialog = False for field in self.fields(): field.useFileInfo = True def updateFileInfo(self, fileObj, fileInfoNode): """Update data of file info node. Arguments: fileObj -- the TreeLine file path object fileInfoNode -- the node to update """ try: status = fileObj.stat() except (AttributeError, OSError): fileInfoNode.data = {} return fileInfoNode.data[FileInfoFormat.fileFieldName] = fileObj.name fileInfoNode.data[FileInfoFormat.pathFieldName] = fileObj.parent fileInfoNode.data[FileInfoFormat.sizeFieldName] = str(status.st_size) modDateTime = datetime.datetime.fromtimestamp(status.st_mtime) modDate = modDateTime.date().strftime(fieldformat.DateField.isoFormat) modTime = modDateTime.time().strftime(fieldformat.TimeField.isoFormat) fileInfoNode.data[FileInfoFormat.dateFieldName] = modDate fileInfoNode.data[FileInfoFormat.timeFieldName] = modTime if not sys.platform.startswith('win'): try: owner = pwd.getpwuid(status.st_uid)[0] except KeyError: owner = repr(status.st_uid) fileInfoNode.data[FileInfoFormat.ownerFieldName] = owner def duplicateFileInfo(self, altFileFormat): """Copy field format settings from alternate file format. Arguments: altFileFormat -- the file info format to copy from """ for field in self.fields(): altField = altFileFormat.fieldDict.get(field.name) if altField: if field.format != altField.format: field.setFormat(altField.format) self.fieldFormatModified = True if altField.prefix: field.prefix = altField.prefix self.fieldFormatModified = True if altField.suffix: field.suffix = altField.suffix self.fieldFormatModified = True class DescendantCountFormat(NodeFormat): """Placeholder format for child count fields. Should not show up in main format type list. """ countFieldName = 'Level' def __init__(self): super().__init__('CountFormat', None) for level in range(3): name = '{0}{1}'.format(DescendantCountFormat.countFieldName, level + 1) field = fieldformat.DescendantCountField(name, level + 1) self.fieldDict[name] = field TreeLine-3.2.1/source/numbering.py000066400000000000000000000155531506556630100171040ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # numbering.py, provides classes to format node numbering # # TreeLine, an information storage program # Copyright (C) 2019, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re class NumberingGroup: """Class to store a multi-level numbering format and apply it. """ def __init__(self, numFormat=''): """Initialize a multi-level numbering format. Arguments: numFormat -- a string describing the format """ self.basicFormats = [] self.sectionStyle = False if numFormat: self.setFormat(numFormat) def setFormat(self, numFormat): """Set a new number format. Arguments: numFormat -- a string describing the format """ self.sectionStyle = False formats = _splitText(numFormat.replace('..', '.'), '/') if len(formats) < 2: formats = _splitText(numFormat.replace('//', '/'), '.') if len(formats) > 1: self.sectionStyle = True self.basicFormats = [BasicNumbering(numFormat) for numFormat in formats] def numString(self, inputNumStr): """Return a number string for the given level and input. The current numbering level is the segment length of the input. Raises ValueError on a bad input string. Arguments: inputNumStr -- a dot-separated string of integers """ if not inputNumStr: return '' inputNums = [int(num) for num in inputNumStr.split('.')] if self.sectionStyle: basicFormats = self.basicFormats[:] if len(basicFormats) < len(inputNums): basicFormats.extend([basicFormats[-1]] * (len(inputNums) - len(basicFormats))) results = [basicFormat.numString(num) for basicFormat, num in zip(basicFormats, inputNums)] return '.'.join(results) else: level = len(inputNums) - 1 try: basicFormat = self.basicFormats[level] except IndexError: basicFormat = self.basicFormats[-1] return basicFormat.numString(inputNums[level]) _formatRegEx = re.compile(r'(.*?)([1AaIi]{1,2})(\W*)$') class BasicNumbering: """Class to store an individaul numbering format and apply it. """ def __init__(self, numFormat=''): """Initialize a basic numbering format. Arguments: numFormat -- a string describing the format """ self.numFunction = _stringFromNum self.upperCase = True self.prefix = '' self.suffix = '' if numFormat: self.setFormat(numFormat) def setFormat(self, numFormat): """Set a new number format. Arguments: numFormat -- a string describing the format """ match = _formatRegEx.match(numFormat) if match: self.prefix, series, self.suffix = match.groups() if series == '1': self.numFunction = _stringFromNum elif series in 'Aa': self.numFunction = _alphaFromNum elif series in 'AAaa': self.numFunction = _alpha2FromNum else: self.numFunction = _romanFromNum self.upperCase = series.isupper() else: self.prefix = numFormat self.numFunction = _stringFromNum def numString(self, num): """Return a number string for the given integer. Arguments: num -- the integer to convert """ return '{0}{1}{2}'.format(self.prefix, self.numFunction(num, self.upperCase), self.suffix) def _stringFromNum(num, case=None): """Return a number string from an integer. Arguments: num -- the integer to convert case -- an unused placeholder """ if num > 0: return repr(num) return '' def _alphaFromNum(num, upperCase=True): """Return an alphabetic string from an integer. Sequence is 'A', 'B' ... 'Z', 'AA', 'BB' ... 'ZZ', 'AAA', 'BBB' ... Arguments: num -- the integer to convert upperCase -- return an upper case string if true """ if num <= 0: return '' result = '' charPos = (num - 1) % 26 char = chr(charPos + ord('A')) qty = (num - 1) // 26 + 1 result = char * qty if not upperCase: result = result.lower() return result def _alpha2FromNum(num, upperCase=True): """Return an alphabetic string from an integer. Sequence is 'AA', 'BB' ... 'ZZ', 'AAA', 'BBB' ... 'ZZZ', 'AAAA', 'BBBB' ... Arguments: num -- the integer to convert upperCase -- return an upper case string if true """ if num <= 0: return '' result = '' charPos = (num - 1) % 26 char = chr(charPos + ord('A')) qty = (num - 1) // 26 + 2 result = char * qty if not upperCase: result = result.lower() return result _romanDict = {0: '', 1: 'I', 2: 'II', 3: 'III', 4: 'IV', 5: 'V', 6: 'VI', 7: 'VII', 8: 'VIII', 9: 'IX', 10: 'X', 20: 'XX', 30: 'XXX', 40: 'XL', 50: 'L', 60: 'LX', 70: 'LXX', 80: 'LXXX', 90: 'XC', 100: 'C', 200: 'CC', 300: 'CCC', 400: 'CD', 500: 'D', 600: 'DC', 700: 'DCC', 800: 'DCCC', 900: 'CM', 1000: 'M', 2000: 'MM', 3000: 'MMM'} def _romanFromNum(num, upperCase=True): """Return a roman numeral string from an integer. Arguments: num -- the integer to convert upperCase -- return an upper case string if true """ if num <= 0 or num >= 4000: return '' result = '' factor = 1000 while num: digit = num - (num % factor) result += _romanDict[digit] factor = factor // 10 num -= digit if not upperCase: result = result.lower() return result def _splitText(textStr, delimitChar): """Split text using the given delimitter and return a list. Double delimitters are not split and empty parts are ignored. Arguments: textStr -- the text to split delimitChar -- the delimitter """ result = [] textStr = textStr.replace(delimitChar * 2, '\0') for text in textStr.split(delimitChar): text = text.replace('\0', delimitChar) if text: result.append(text) return result TreeLine-3.2.1/source/optiondefaults.py000066400000000000000000000364131506556630100201540ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # optiondefaults.py, defines defaults for config options # # TreeLine, an information storage program # Copyright (C) 2022, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import options daysOfWeek = [_('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday'), _('Sunday')] # colorThemes = [_('Normal'), _('Dark')] def setGenOptionDefaults(generalOptions): """Set defaults for general config options. """ StringOptionItem = options.StringOptionItem IntOptionItem = options.IntOptionItem BoolOptionItem = options.BoolOptionItem ListOptionItem = options.ListOptionItem BoolOptionItem(generalOptions, 'AutoFileOpen', False, _('Startup Condition'), _('Automatically open last file used')) BoolOptionItem(generalOptions, 'InitShowBreadcrumb', True, _('Startup Condition'), _('Show breadcrumb ancestor view')) BoolOptionItem(generalOptions, 'InitShowChildPane', True, _('Startup Condition'), _('Show child pane in right hand views')) BoolOptionItem(generalOptions, 'InitShowDescendants', False, _('Startup Condition'), _('Show descendants in output view')) BoolOptionItem(generalOptions, 'SaveTreeStates', True, _('Startup Condition'), _('Restore tree view states of recent files')) BoolOptionItem(generalOptions, 'PurgeRecentFiles', True, _('Startup Condition'), _('Remove inaccessible recent file entries')) BoolOptionItem(generalOptions, 'SaveWindowGeom', True, _('Startup Condition'), _('Restore previous window geometry')) BoolOptionItem(generalOptions, 'OpenNewWindow', True, _('Features Available'), _('Open files in new windows')) BoolOptionItem(generalOptions, 'MinToSysTray', False, _('Features Available'), _('Minimize application to system tray')) BoolOptionItem(generalOptions, 'EditorOnHover', True, _('Features Available'), _('Activate data editors on mouse hover')) BoolOptionItem(generalOptions, 'EditorLimitHeight', True, _('Features Available'), _('Limit data editor height to window size')) BoolOptionItem(generalOptions, 'ClickRename', True, _('Features Available'), _('Click node to rename')) BoolOptionItem(generalOptions, 'RenameNewNodes', True, _('Features Available'), _('Rename new nodes when created')) BoolOptionItem(generalOptions, 'DragTree', True, _('Features Available'), _('Tree drag && drop available')) BoolOptionItem(generalOptions, 'PrettyPrint', False, _('Features Available'), _('Indent (pretty print) TreeLine JSON files')) BoolOptionItem(generalOptions, 'ShowTreeIcons', True, _('Features Available'), _('Show icons in the tree view')) BoolOptionItem(generalOptions, 'ShowMath', True, _('Features Available'), _('Show math fields in the Data Edit view')) BoolOptionItem(generalOptions, 'EditNumbering', False, _('Features Available'), _('Show numbering fields in the Data Edit view')) IntOptionItem(generalOptions, 'UndoLevels', 5, 0, 999, _('Undo Memory'), _('Number of undo levels'), 1) IntOptionItem(generalOptions, 'AutoSaveMinutes', 0, 0, 999, _('Auto Save'), _('Minutes between saves\n(set to 0 to disable)'), 1) IntOptionItem(generalOptions, 'RecentFiles', 4, 0, 99, _('Recent Files'), _('Number of recent files \nin the file menu'), 1) StringOptionItem(generalOptions, 'EditTimeFormat', '%-H:%M:%S', False, True, _('Data Editor Formats'), _('Times'), 1) StringOptionItem(generalOptions, 'EditDateFormat', '%m/%d/%y', False, True, _('Data Editor Formats'), _('Dates'), 1) ListOptionItem(generalOptions, 'WeekStart', daysOfWeek[-1], daysOfWeek, _('Data Editor Formats'), _('First day\nof week'), 1) IntOptionItem(generalOptions, 'IndentOffset', 2, 0, 99, _('Appearance'), _('Child indent offset\n(in font height units) '), 1) # ListOptionItem(generalOptions, 'ColorTheme', colorThemes[0], colorThemes, # _('Appearance'), _('Color Theme'), 1) def setMiscOptionDefaults(miscOptions): """Set defaults for miscellaneous config options. """ StringOptionItem = options.StringOptionItem StringOptionItem(miscOptions, 'PrintUnits', 'in', False, True) StringOptionItem(miscOptions, 'SpellCheckPath', '') StringOptionItem(miscOptions, 'AppFont', '', True, True) StringOptionItem(miscOptions, 'TreeFont', '', True, True) StringOptionItem(miscOptions, 'OutputFont', '', True, True) StringOptionItem(miscOptions, 'EditorFont', '', True, True) StringOptionItem(miscOptions, 'ColorTheme', 'system', False, True) StringOptionItem(miscOptions, 'WindowColor', '', True, True) StringOptionItem(miscOptions, 'WindowTextColor', '', True, True) StringOptionItem(miscOptions, 'BaseColor', '', True, True) StringOptionItem(miscOptions, 'TextColor', '', True, True) StringOptionItem(miscOptions, 'HighlightColor', '', True, True) StringOptionItem(miscOptions, 'HighlightedTextColor', '', True, True) StringOptionItem(miscOptions, 'LinkColor', '', True, True) StringOptionItem(miscOptions, 'ToolTipBaseColor', '', True, True) StringOptionItem(miscOptions, 'ToolTipTextColor', '', True, True) StringOptionItem(miscOptions, 'ButtonColor', '', True, True) StringOptionItem(miscOptions, 'ButtonTextColor', '', True, True) StringOptionItem(miscOptions, 'Text-DisabledColor', '', True, True) StringOptionItem(miscOptions, 'ButtonText-DisabledColor', '', True, True) def setHistOptionDefaults(historyOptions): """Set defaults for history config options. """ IntOptionItem = options.IntOptionItem DataListOptionItem = options.DataListOptionItem IntOptionItem(historyOptions, 'WindowXSize', 640, 10, 10000) IntOptionItem(historyOptions, 'WindowYSize', 640, 10, 10000) IntOptionItem(historyOptions, 'WindowXPos', -1000, -1000, 10000) IntOptionItem(historyOptions, 'WindowYPos', -1000, -1000, 10000) IntOptionItem(historyOptions, 'WindowTopMargin', 0, 0, 1000) IntOptionItem(historyOptions, 'WindowOtherMargin', 0, 0, 1000) IntOptionItem(historyOptions, 'CrumbSplitPercent', 10, 1, 99) IntOptionItem(historyOptions, 'TreeSplitPercent', 40, 1, 99) IntOptionItem(historyOptions, 'OutputSplitPercent', 20, 1, 99) IntOptionItem(historyOptions, 'EditorSplitPercent', 25, 1, 99) IntOptionItem(historyOptions, 'TitleSplitPercent', 10, 1, 99) IntOptionItem(historyOptions, 'ActiveRightView', 0, 0, 2) IntOptionItem(historyOptions, 'PrintPrevXSize', 0, 0, 10000) IntOptionItem(historyOptions, 'PrintPrevYSize', 0, 0, 10000) IntOptionItem(historyOptions, 'PrintPrevXPos', -1000, -1000, 10000) IntOptionItem(historyOptions, 'PrintPrevYPos', -1000, -1000, 10000) DataListOptionItem(historyOptions, 'RecentFiles', []) def setToolbarOptionDefaults(toolbarOptions): """Set defaults for toolbar geometry and buttons. """ StringOptionItem = options.StringOptionItem DataListOptionItem = options.DataListOptionItem IntOptionItem = options.IntOptionItem IntOptionItem(toolbarOptions, 'ToolbarQuantity', 2, 0, 20) IntOptionItem(toolbarOptions, 'ToolbarSize', 16, 1, 128) StringOptionItem(toolbarOptions, 'ToolbarPosition', '') DataListOptionItem(toolbarOptions, 'ToolbarCommands', ['FileNew,FileOpen,FileSave,,FilePrintPreview,' 'FilePrint,,EditUndo,EditRedo,,EditCut,EditCopy,' 'EditPaste,,DataConfigType,ToolsFindText', 'NodeInsertAfter,NodeAddChild,,NodeDelete,NodeIndent,' 'NodeUnindent,,NodeMoveUp,NodeMoveDown,,' 'ViewExpandBranch,ViewCollapseBranch,,' 'ViewPrevSelect,ViewNextSelect,,ViewShowDescend']) def setKeyboardOptionDefaults(keyboardOptions): """Set defaults for keyboard shortcuts. """ KeyOptionItem = options.KeyOptionItem KeyOptionItem(keyboardOptions, 'FileNew', 'Ctrl+N', 'File Menu') KeyOptionItem(keyboardOptions, 'FileOpen', 'Ctrl+O', 'File Menu') KeyOptionItem(keyboardOptions, 'FileOpenSample', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FileImport', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FileSave', 'Ctrl+S', 'File Menu') KeyOptionItem(keyboardOptions, 'FileSaveAs', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FileExport', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FileProperties', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FilePrintSetup', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FilePrintPreview', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FilePrint', 'Ctrl+P', 'File Menu') KeyOptionItem(keyboardOptions, 'FilePrintPdf', '', 'File Menu') KeyOptionItem(keyboardOptions, 'FileQuit', 'Ctrl+Q', 'File Menu') KeyOptionItem(keyboardOptions, 'EditUndo', 'Ctrl+Z', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditRedo', 'Ctrl+Y', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditCut', 'Ctrl+X', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditCopy', 'Ctrl+C', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPaste', 'Ctrl+V', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPastePlain', '', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPasteChild', '', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPasteBefore', '', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPasteAfter', '', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPasteCloneChild', '', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPasteCloneBefore', '', 'Edit Menu') KeyOptionItem(keyboardOptions, 'EditPasteCloneAfter', '', 'Edit Menu') KeyOptionItem(keyboardOptions, 'NodeRename', 'Ctrl+R', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeAddChild', 'Ctrl+A', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeInsertBefore', 'Ctrl+B', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeInsertAfter', 'Ctrl+I', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeDelete', 'Del', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeIndent', 'Ctrl+Shift+Right', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeUnindent', 'Ctrl+Shift+Left', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeMoveUp', 'Ctrl+Shift+Up', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeMoveDown', 'Ctrl+Shift+Down', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeMoveFirst', '', 'Node Menu') KeyOptionItem(keyboardOptions, 'NodeMoveLast', '', 'Node Menu') KeyOptionItem(keyboardOptions, 'DataNodeType', 'Ctrl+T', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataConfigType', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataCopyType', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataVisualConfig', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataSortNodes', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataNumbering', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataRegenRefs', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataCloneMatches', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataDetachClones', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataFlatCategory', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataAddCategory', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'DataSwapCategory', '', 'Data Menu') KeyOptionItem(keyboardOptions, 'ToolsFindText', 'Ctrl+F', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsFindCondition', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsFindReplace', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsFilterText', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsFilterCondition', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsSpellCheck', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsGenOptions', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsShortcuts', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsToolbars', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsFonts', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'ToolsColors', '', 'Tools Menu') KeyOptionItem(keyboardOptions, 'FormatBoldFont', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatItalicFont', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatUnderlineFont', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatStrikethroughFont', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatFontSize', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatFontColor', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatExtLink', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatIntLink', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatInsertDate', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatSelectAll', 'Ctrl+L', 'Format Menu') KeyOptionItem(keyboardOptions, 'FormatClearFormat', '', 'Format Menu') KeyOptionItem(keyboardOptions, 'ViewExpandBranch', 'Ctrl+Right', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewCollapseBranch', 'Ctrl+Left', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewPrevSelect', 'Ctrl+Shift+P', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewNextSelect', 'Ctrl+Shift+N', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewDataOutput', 'Ctrl+Shift+O', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewDataEditor', 'Ctrl+Shift+E', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewTitleList', 'Ctrl+Shift+T', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewBreadcrumb', '', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewShowChildPane', 'Ctrl+Shift+C', 'View Menu') KeyOptionItem(keyboardOptions, 'ViewShowDescend', 'Ctrl+Shift+D', 'View Menu') KeyOptionItem(keyboardOptions, 'WinNewWindow', '', 'Window Menu') KeyOptionItem(keyboardOptions, 'WinCloseWindow', '', 'Window Menu') KeyOptionItem(keyboardOptions, 'HelpBasic', '', 'Help Menu') KeyOptionItem(keyboardOptions, 'HelpFull', '', 'Help Menu') KeyOptionItem(keyboardOptions, 'HelpAbout', '', 'Help Menu') KeyOptionItem(keyboardOptions, 'IncremSearchStart', 'Ctrl+/', 'No Menu') KeyOptionItem(keyboardOptions, 'IncremSearchNext', 'F3', 'No Menu') KeyOptionItem(keyboardOptions, 'IncremSearchPrev', 'Shift+F3', 'No Menu') TreeLine-3.2.1/source/options.py000066400000000000000000000656551506556630100166210ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # options.py, provides a class to manage config options # # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** from collections import OrderedDict import sys import re import pathlib import os.path import json from PyQt6.QtCore import Qt from PyQt6.QtGui import QKeySequence from PyQt6.QtWidgets import (QButtonGroup, QCheckBox, QComboBox, QDialog, QDoubleSpinBox, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QPushButton, QRadioButton, QSpinBox, QVBoxLayout) import miscdialogs multipleSpaceRegEx = re.compile(r' {2,}') class StringOptionItem: """Class to store and control a string-based config option entry. Stores the name, value, category and description, provides validation, config file output and dialog controls. """ def __init__(self, optionDict, name, value, emptyOK=True, stripSpaces=False, category='', description='', columnNum=0): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- the string value emptyOK -- if False, does not allow empty string stripSpaces -- if True, remove leading, trailing & double spaces category -- a string for the option group this belongs to description -- a string for use in the control dialog columnNum -- the column position for this control in the dialog """ self.name = name self.category = category self.description = description self.columnNum = columnNum self.emptyOK = emptyOK self.stripSpaces = stripSpaces self.dialogControl = None self.value = None self.setValue(value) self.defaultValue = self.value optionDict[name] = self def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- the string value to set """ value = str(value) if self.stripSpaces: value = multipleSpaceRegEx.sub(' ', value.strip()) if value != self.value and (value or self.emptyOK): self.value = value return True if self.value == None: raise ValueError return False def storedValue(self): """Return the value to be stored in the JSON file. """ return self.value def addDialogControl(self, groupBox): """Add the labels and controls to a dialog box for this option item. Arguments: groupBox -- the current group box """ gridLayout = groupBox.layout() row = gridLayout.rowCount() label = QLabel(self.description, groupBox) gridLayout.addWidget(label, row, 0) self.dialogControl = QLineEdit(self.value, groupBox) gridLayout.addWidget(self.dialogControl, row, 1) def updateFromDialog(self): """Set the value of this item from the dialog contents. Return True if successfully set. """ return self.setValue(self.dialogControl.text()) class IntOptionItem(StringOptionItem): """Class to store and control an integer-based config option entry. Stores the name, value, category and description, provides validation, config file output and dialog controls. """ def __init__(self, optionDict, name, value, minimum=None, maximum=None, category='', description='', columnNum=0): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- a numeric or string-based value minimum -- optional minimum value maximum -- optional maximum value category -- a string for the option group this belongs to description -- a string for use in the control dialog columnNum -- the column position for this control in the dialog """ self.minimum = minimum self.maximum = maximum super().__init__(optionDict, name, value, False, False, category, description, columnNum) def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- a numeric or string-based value to set """ try: value = int(value) if self.minimum != None and value < self.minimum: raise ValueError if self.maximum != None and value > self.maximum: raise ValueError except ValueError: if self.value == None: raise return False if value != self.value: self.value = value return True return False def addDialogControl(self, groupBox): """Add the labels and controls to a dialog box for this option item. Arguments: groupBox -- the current group box """ gridLayout = groupBox.layout() row = gridLayout.rowCount() label = QLabel(self.description, groupBox) gridLayout.addWidget(label, row, 0) self.dialogControl = QSpinBox(groupBox) self.dialogControl.setValue(self.value) if self.minimum != None: self.dialogControl.setMinimum(self.minimum) if self.maximum != None: self.dialogControl.setMaximum(self.maximum) gridLayout.addWidget(self.dialogControl, row, 1) def updateFromDialog(self): """Set the value of this item from the dialog contents. Return True if successfully set. """ return self.setValue(self.dialogControl.value()) class FloatOptionItem(StringOptionItem): """Class to store and control a float-based config option entry. Stores the name, value, category and description, provides validation, config file output and dialog controls. """ def __init__(self, optionDict, name, value, minimum=None, maximum=None, category='', description='', columnNum=0): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- a numeric or string-based value minimum -- optional minimum value maximum -- optional maximum value category -- a string for the option group this belongs to description -- a string for use in the control dialog columnNum -- the column position for this control in the dialog """ self.minimum = minimum self.maximum = maximum super().__init__(optionDict, name, value, False, False, category, description, columnNum) def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- a numeric or string-based value to set """ try: value = float(value) if self.minimum != None and value < self.minimum: raise ValueError if self.maximum != None and value > self.maximum: raise ValueError except ValueError: if self.value == None: raise return False if value != self.value: self.value = value return True return False def addDialogControl(self, groupBox): """Add the labels and controls to a dialog box for this option item. Arguments: groupBox -- the current group box """ gridLayout = groupBox.layout() row = gridLayout.rowCount() label = QLabel(self.description, groupBox) gridLayout.addWidget(label, row, 0) self.dialogControl = QDoubleSpinBox(groupBox) self.dialogControl.setValue(self.value) if self.minimum != None: self.dialogControl.setMinimum(self.minimum) if self.maximum != None: self.dialogControl.setMaximum(self.maximum) gridLayout.addWidget(self.dialogControl, row, 1) def updateFromDialog(self): """Set the value of this item from the dialog contents. Return True if successfully set. """ return self.setValue(self.dialogControl.value()) class BoolOptionItem(StringOptionItem): """Class to store and control a boolean config option entry. Stores the name, value, category and description, provides validation, config file output and dialog controls. """ def __init__(self, optionDict, name, value, category='', description='', columnNum=0): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- the boolean or string value category -- a string for the option group this belongs to description -- a string for use in the control dialog columnNum -- the column position for this control in the dialog """ super().__init__(optionDict, name, value, False, False, category, description, columnNum) def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- a boolean or string-based value to set """ if hasattr(value, 'lower'): if value.lower() in ('yes', 'y', 'true'): value = True elif value.lower() in ('no', 'n', 'false'): value = False else: value = bool(value) if value in (True, False) and value != self.value: self.value = value return True if self.value == None: raise ValueError return False def addDialogControl(self, groupBox): """Add the labels and controls to a dialog box for this option item. Arguments: groupBox -- the current group box """ gridLayout = groupBox.layout() row = gridLayout.rowCount() self.dialogControl = QCheckBox(self.description, groupBox) self.dialogControl.setChecked(self.value) gridLayout.addWidget(self.dialogControl, row, 0, 1, 2) def updateFromDialog(self): """Set the value of this item from the dialog contents. Return True if successfully set. """ return self.setValue(self.dialogControl.isChecked()) class ListOptionItem(StringOptionItem): """Class to store and control a pull-down list config option entry. Stores the name, value, category and description, provides validation, config file output and dialog controls. """ def __init__(self, optionDict, name, value, choices, category='', description='', columnNum=0): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- the string value choices -- a list of acceptable entries category -- a string for the option group this belongs to description -- a string for use in the control dialog columnNum -- the column position for this control in the dialog """ self.choices = choices super().__init__(optionDict, name, value, False, False, category, description, columnNum) def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- the string value to set """ value = str(value) if value in self.choices and value != self.value: self.value = value return True if self.value == None: raise ValueError return False def addDialogControl(self, groupBox): """Add the labels and controls to a dialog box for this option item. Arguments: groupBox -- the current group box """ gridLayout = groupBox.layout() row = gridLayout.rowCount() label = QLabel(self.description, groupBox) gridLayout.addWidget(label, row, 0) self.dialogControl = QComboBox(groupBox) self.dialogControl.addItems(self.choices) self.dialogControl.setCurrentIndex(self.choices.index(self.value)) gridLayout.addWidget(self.dialogControl, row, 1) def updateFromDialog(self): """Set the value of this item from the dialog contents. Return True if successfully set. """ return self.setValue(self.dialogControl.currentText()) class ChoiceOptionItem(StringOptionItem): """Class to store and control a radio button choice config option entry. Stores the name, value, category and description, provides validation, config file output and dialog controls. """ def __init__(self, optionDict, name, value, choices, category='', columnNum=0): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- the string value choices -- a list of acceptable entries category -- a string for the option group this belongs to columnNum -- the column position for this control in the dialog """ self.choices = choices super().__init__(optionDict, name, value, False, False, category, '', columnNum) def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- the string value to set """ value = str(value) if value in self.choices and value != self.value: self.value = value return True if self.value == None: raise ValueError return False def addDialogControl(self, groupBox): """Add the labels and controls to a dialog box for this option item. Arguments: groupBox -- the current group box """ rowLayout.addWidget(groupBox) QGridLayout(groupBox) gridLayout = groupBox.layout() self.dialogControl = QButtonGroup(groupBox) row = 0 for choice in self.choices: button = QRadioButton(choice, groupBox) self.dialogControl.addButton(button) gridLayout.addWidget(button, row, 0, 1, 2) row += 1 def updateFromDialog(self): """Set the value of this item from the dialog contents. Return True if successfully set. """ return self.setValue(self.dialogControl.checkedButton().text()) class KeyOptionItem(StringOptionItem): """Class to store and control a keyboard key based config option entry. Stores the name, value and category, provides validation and config file output. """ def __init__(self, optionDict, name, value, category=''): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- a numeric or string-based value category -- a string for the option group this belongs to """ super().__init__(optionDict, name, value, True, False, category) def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- a key string value to set """ key = QKeySequence(value) if value and key.isEmpty(): if self.value == None: raise ValueError return False if value != self.value: self.value = key return True return False def storedValue(self): """Return the value to be stored in the JSON file. """ return self.value.toString() class DataListOptionItem(StringOptionItem): """Class to store an arbitrary length list containing various data. Stores the name and value, provides validation and config file output. """ def __init__(self, optionDict, name, value): """Set the parameters and initial value and add to optionDict. Raises a ValueError if initial validation fails. Arguments: optionDict -- a dictionary to add this option item to name -- the string key for the option value -- a list containg other basic data types """ super().__init__(optionDict, name, value) def setValue(self, value): """Sets the value and validates, returns True if OK. Returns False if validation fails but the old value is OK, or if the value is unchanged. Raises a ValueError if validation fails without an old value. Arguments: value -- a list containg other basic data types """ if isinstance(value, list) and value != self.value: self.value = value return True if self.value == None: raise ValueError return False class Options(OrderedDict): """Class to store and control the config options for a program. """ basePath = None def __init__(self, fileName='', progName='', version='', coDirName=''): """Initialize and set the path to the config file. Creates the path dir structure if necessary (if fileName is given). On Windows, uses the module path's config directory if it exists. Arguments: fileName -- the config file name, excluding the extension progName -- the program name, for dialog headings & config dir name version -- a version string, for config dir names coDirName -- the company name for the config dir in Windows OS """ super().__init__() self.modified = False self.path = pathlib.Path() if not fileName: return # no storage without fileName (temporary options only) if not version: version = '0' appDirName = '{0}-{1}'.format(progName.lower(), version) fileNameSuffix = '.ini' if sys.platform.startswith('win') else 'rc' if not Options.basePath and progName and coDirName: if sys.platform.startswith('win'): # Windows userPath = (pathlib.Path(os.environ.get('APPDATA', '')) / coDirName / appDirName) else: # Linux, etc. userPath = (pathlib.Path(os.path.expanduser('~')) / ('.' + appDirName)) if userPath.is_dir(): Options.basePath = userPath else: # use abspath() - pathlib's resolve() buggy with network drives modPath = pathlib.Path(os.path.abspath(sys.path[0])) if modPath.is_file(): modPath = modPath.parent # for frozen binary modConfigPath = modPath / 'config' if modConfigPath.is_dir(): Options.basePath = modConfigPath elif os.access(str(modPath), os.W_OK): dialog = miscdialogs.RadioChoiceDialog(progName, _('Choose configuration file location'), [(_('User\'s home directory (recommended)'), 0), (_('Program directory (for portable use)'), 1)]) if dialog.exec() != QDialog.DialogCode.Accepted: sys.exit(0) if dialog.selectedButton() == 1: Options.basePath = modConfigPath if not Options.basePath: Options.basePath = userPath try: if not Options.basePath.is_dir(): Options.basePath.mkdir(parents=True) iconPath = Options.basePath / 'icons' if not iconPath.is_dir(): iconPath.mkdir() templatePath = Options.basePath / 'templates' if not templatePath.is_dir(): templatePath.mkdir() templateExportPath = templatePath / 'exports' if not templateExportPath.is_dir(): templateExportPath.mkdir() except OSError: Options.basePath = None if Options.basePath: self.path = Options.basePath / (fileName + fileNameSuffix) def __getitem__(self, name): """Return the value of an option when called as options[name]. Arguments: name -- the string key for the option """ return self.get(name).value def getDefaultValue(self, name): """Return the initially set default value from the given option key. Arguments: name -- the string key for the option """ return self.get(name).defaultValue def changeValue(self, name, value): """Set a new value for the given option key. Return True if sucessful. Arguments: name -- the string key for the option value -- a value or a string defining the value """ if self.get(name).setValue(value): self.modified = True return True return False def resetToDefaults(self, keyList): """Reset all options with the given keys to original default values. Arguments: keyList -- a list of option names to reset """ for key in keyList: self.get(key).setValue(self.get(key).defaultValue) self.modified = True def removeValue(self, name): """Remove the value from the option list if possible. If not, fail silently. Arguments: name -- the string key for the option to be removed """ try: del self[name] except KeyError: return self.modified = True def readFile(self): """Read config options from the file on self.path. Create the file if it isn't found, raise IOError if this fails. Only updates existing config items. """ try: with self.path.open('r', encoding='utf-8') as f: data = json.load(f) for key, value in data.items(): try: self.get(key).setValue(value) except AttributeError: pass except (IOError, ValueError): if not self.writeFile(): raise IOError def writeFile(self): """Write current options to the file on self.path. Returns False on failure. """ try: with self.path.open('w', encoding='utf-8') as f: data = OrderedDict([(key, obj.storedValue()) for (key, obj) in self.items()]) json.dump(data, f, indent=0) self.modified = False except IOError: return False return True class OptionDialog(QDialog): """Provides a dialog with controls for all options in an Options instance. """ def __init__(self, options, parent=None): super().__init__(parent) self.options = options self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) topLayout = QVBoxLayout(self) self.setLayout(topLayout) columnLayout = QHBoxLayout() topLayout.addLayout(columnLayout) rowLayout = QVBoxLayout() columnLayout.addLayout(rowLayout) groupBox = None for option in self.options.values(): if option.columnNum > columnLayout.count() - 1: rowLayout = QVBoxLayout() columnLayout.addLayout(rowLayout) if not groupBox or groupBox.title() != option.category: groupBox = QGroupBox(option.category) rowLayout.addWidget(groupBox) QGridLayout(groupBox) option.addDialogControl(groupBox) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch(0) okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) def accept(self): """Updates the options from the controls when the OK button is pressed. """ for option in self.options.values(): if option.updateFromDialog(): self.options.modified = True super().accept() TreeLine-3.2.1/source/outputview.py000066400000000000000000000140071506556630100173420ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # outputview.py, provides a class for the data output view # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** from PyQt6.QtCore import Qt from PyQt6.QtGui import QPalette, QTextCursor from PyQt6.QtWidgets import QTextBrowser, QTextEdit import treeoutput import urltools import dataeditors import globalref class OutputView(QTextBrowser): """Class override for the data output view. Sets view defaults and updates the content. """ def __init__(self, treeView, isChildView=True, parent=None): """Initialize the output view. Arguments: treeView - the tree view, needed for the current selection model isChildView -- shows selected nodes if false, child nodes if true parent -- the parent main window """ super().__init__(parent) self.treeView = treeView self.isChildView = isChildView self.hideChildView = not globalref.genOptions['InitShowChildPane'] self.showDescendants = globalref.genOptions['InitShowDescendants'] self.setFocusPolicy(Qt.FocusPolicy.NoFocus) def updateContents(self): """Reload the view's content if the view is shown. Avoids update if view is not visible or has zero height or width. """ selSpots = self.treeView.selectionModel().selectedSpots() if self.isChildView: if (len(selSpots) > 1 or self.hideChildView or (selSpots and not selSpots[0].nodeRef.childList)): self.hide() return if not selSpots: # use top node childList from tree structure selSpots = [globalref.mainControl.activeControl.structure. structSpot()] elif not selSpots: self.hide() return self.show() if not self.isVisible() or self.height() == 0 or self.width() == 0: return if self.isChildView: if self.showDescendants: outputGroup = treeoutput.OutputGroup(selSpots, False, True) if outputGroup.hasPrefixes(): outputGroup.combineAllSiblings() outputGroup.addBlanksBetween() outputGroup.addAbsoluteIndents() else: outputGroup = treeoutput.OutputGroup(selSpots[0].childSpots()) outputGroup.addBlanksBetween() outputGroup.addSiblingPrefixes() else: outputGroup = treeoutput.OutputGroup(selSpots) outputGroup.addBlanksBetween() outputGroup.addSiblingPrefixes() self.setHtml('\n'.join(outputGroup.getLines())) self.setSearchPaths([str(globalref.mainControl.defaultPathObj(True))]) def doSetSource(self, url, resType): """Called when a user clicks on a URL link. Selects an internal link or opens an external browser. Arguments: url -- the QUrl that is clicked """ name = url.toString() if name.startswith('#'): if not self.treeView.selectionModel().selectNodeById(name[1:]): super().doSetSource(url, resType) else: if urltools.isRelative(name): # check for relative path defaultPath = globalref.mainControl.defaultPathObj(True) name = urltools.toAbsolute(name, str(defaultPath)) dataeditors.openExtUrl(name) def hasSelectedText(self): """Return True if text is selected. """ return self.textCursor().hasSelection() def highlightSearch(self, wordList=None, regExpList=None): """Highlight any found search terms. Arguments: wordList -- list of words to highlight regExpList -- a list of regular expression objects to highlight """ backColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.Highlight) foreColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.HighlightedText) if wordList is None: wordList = [] if regExpList is None: regExpList = [] for regExp in regExpList: for match in regExp.finditer(self.toPlainText()): matchText = match.group() if matchText not in wordList: wordList.append(matchText) selections = [] for word in wordList: while self.find(word): extraSel = QTextEdit.ExtraSelection() extraSel.cursor = self.textCursor() extraSel.format.setBackground(backColor) extraSel.format.setForeground(foreColor) selections.append(extraSel) cursor = QTextCursor(self.document()) self.setTextCursor(cursor) # reset main cursor/selection self.setExtraSelections(selections) def contextMenuEvent(self, event): """Add a popup menu for select all and copy actions. Arguments: event -- the menu event """ menu = self.createStandardContextMenu() menu.removeAction(menu.actions()[1]) #remove copy link location menu.exec(event.globalPos()) def resizeEvent(self, event): """Update view if was collaped by splitter. """ if ((event.oldSize().height() == 0 and event.size().height()) or (event.oldSize().width() == 0 and event.size().width())): self.updateContents() return super().resizeEvent(event) TreeLine-3.2.1/source/p3.py000066400000000000000000000121521506556630100154300ustar00rootroot00000000000000#!/usr/bin/env python3 # Simple p3 encryption "algorithm": it's just SHA used as a stream # cipher in output feedback mode. # Author: Paul Rubin, Fort GNOX Cryptography, . # Algorithmic advice from David Wagner, Richard Parker, Bryan # Olson, and Paul Crowley on sci.crypt is gratefully acknowledged. # Copyright 2002,2003 by Paul Rubin # Copying license: same as Python 2.3 license # Please include this revision number in any bug reports: $Revision: 1.2 $. # Modified by Doug Bell to be compatible with Python 3 from array import array from time import time import struct import hashlib shaHash = hashlib.sha1 class CryptError(Exception): pass def _hash(text): return shaHash(text).digest() _ivlen = 16 _maclen = 8 _state = _hash(repr(time()).encode()) # added by Doug Bell for compatibility with 64-bit systems _arraytype = [t for t in 'LIH' if struct.calcsize(t) == 4][0] try: import os _pid = repr(os.getpid()).encode() except (ImportError, AttributeError): _pid = '' def _expand_key(key, clen): blocks = (clen+19)//20 xkey=[] seed=key for i in range(blocks): seed=shaHash(key+seed).digest() xkey.append(seed) j = b''.join(xkey) return array(_arraytype, j) def p3_encrypt(plain,key): global _state H = _hash # change _state BEFORE using it to compute nonce, in case there's # a thread switch between computing the nonce and folding it into # the state. This way if two threads compute a nonce from the # same data, they won't both get the same nonce. (There's still # a small danger of a duplicate nonce--see below). _state = b'X'+_state # Attempt to make nlist unique for each call, so we can get a # unique nonce. It might be good to include a process ID or # something, but I don't know if that's portable between OS's. # Since is based partly on both the key and plaintext, in the # worst case (encrypting the same plaintext with the same key in # two separate Python instances at the same time), you might get # identical ciphertexts for the identical plaintexts, which would # be a security failure in some applications. Be careful. nlist = [repr(time()).encode(), _pid, _state, repr(len(plain)).encode(),plain, key] nonce = H(b','.join(nlist))[:_ivlen] _state = H(b'update2'+_state+nonce) k_enc, k_auth = H(b'enc'+key+nonce), H(b'auth'+key+nonce) n=len(plain) # cipher size not counting IV stream = array(_arraytype, plain+b'0000'[n&3:]) # pad to fill 32-bit words xkey = _expand_key(k_enc, n+4) for i in range(len(stream)): stream[i] = stream[i] ^ xkey[i] ct = nonce + stream.tobytes()[:n] auth = _hmac(ct, k_auth) return ct + auth[:_maclen] def p3_decrypt(cipher,key): H = _hash n=len(cipher)-_ivlen-_maclen # length of ciphertext if n < 0: raise CryptError("invalid ciphertext") nonce,stream,auth = \ cipher[:_ivlen], cipher[_ivlen:-_maclen]+b'0000'[n&3:],cipher[-_maclen:] k_enc, k_auth = H(b'enc'+key+nonce), H(b'auth'+key+nonce) vauth = _hmac (cipher[:-_maclen], k_auth)[:_maclen] if auth != vauth: raise CryptError("invalid key or ciphertext") stream = array(_arraytype, stream) xkey = _expand_key (k_enc, n+4) for i in range (len(stream)): stream[i] = stream[i] ^ xkey[i] plain = stream.tobytes()[:n] return plain # RFC 2104 HMAC message authentication code # This implementation is faster than Python 2.2's hmac.py, and also works in # old Python versions (at least as old as 1.5.2). def _hmac_setup(): global _ipad, _opad, _itrans, _otrans _itrans = array('B',[0]*256) _otrans = array('B',[0]*256) for i in range(256): _itrans[i] = i ^ 0x36 _otrans[i] = i ^ 0x5c _itrans = _itrans.tobytes() _otrans = _otrans.tobytes() _ipad = b'\x36'*64 _opad = b'\x5c'*64 def _hmac(msg, key): if len(key)>64: key=shaHash(key).digest() ki = (key.translate(_itrans)+_ipad)[:64] # inner ko = (key.translate(_otrans)+_opad)[:64] # outer return shaHash(ko+shaHash(ki+msg).digest()).digest() # # benchmark and unit test # def _time_p3(n=1000,len=20): plain="a"*len t=time() for i in range(n): p3_encrypt(plain,b"abcdefgh") dt=time()-t print("plain p3:", n,len,dt,"sec =",n*len//dt,"bytes/sec") def _speed(): _time_p3(len=5) _time_p3() _time_p3(len=200) _time_p3(len=2000,n=100) def _test(): e=p3_encrypt d=p3_decrypt plain=b"test plaintext" key = b"test key" c1 = e(plain,key) c2 = e(plain,key) assert c1!=c2 assert d(c2,key)==plain assert d(c1,key)==plain c3 = c2[:20]+chr(1+c2[20]).encode()+c2[21:] # change one ciphertext char try: print(d(c3,key)) # should throw exception print("auth verification failure") except CryptError: pass try: print(d(c2,b'wrong key')) # should throw exception print("test failure") except CryptError: pass _hmac_setup() # _test() # _speed() # uncomment to run speed test TreeLine-3.2.1/source/printdata.py000066400000000000000000000662211506556630100171020ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # printdata.py, provides a class for printing # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import os.path import enum from PyQt6.QtCore import QMarginsF, QSizeF, Qt from PyQt6.QtGui import (QAbstractTextDocumentLayout, QFontMetrics, QPageLayout, QPageSize, QPainter, QPalette, QTextDocument) from PyQt6.QtWidgets import QApplication, QDialog, QFileDialog, QMessageBox from PyQt6.QtPrintSupport import QPrintDialog, QPrinter import treeoutput import printdialogs import globalref PrintScope = enum.IntEnum('PrintScope', 'entireTree selectBranch selectNode') _defaultMargin = 0.5 _defaultHeaderPos = 0.2 _defaultColumnSpace = 0.5 class PrintData: """Class to handle printing of tree output data. Stores print data and main printing functions. """ def __init__(self, localControl): """Initialize the print data. Arguments: localControl -- a reference to the parent local control """ self.localControl = localControl self.outputGroup = None self.printWhat = PrintScope.entireTree self.includeRoot = True self.openOnly = False self.printer = QPrinter(QPrinter.PrinterMode.HighResolution) self.pageLayout = self.printer.pageLayout() self.setDefaults() self.adjustSpacing() def setDefaults(self): """Set all paparmeters saved in TreeLine files to default values. """ self.drawLines = True self.widowControl = True self.indentFactor = 2.0 self.pageLayout.setUnits(QPageLayout.Unit.Inch) self.pageLayout.setPageSize(QPageSize(QPageSize.PageSizeId.Letter)) self.pageLayout.setOrientation(QPageLayout.Orientation.Portrait) self.pageLayout.setMargins(QMarginsF(*(_defaultMargin,) * 4)) self.headerMargin = _defaultHeaderPos self.footerMargin = _defaultHeaderPos self.numColumns = 1 self.columnSpacing = _defaultColumnSpace self.headerText = '' self.footerText = '' self.useDefaultFont = True self.setDefaultFont() def setDefaultFont(self): """Set the default font initially and based on an output font change. """ self.defaultFont = QTextDocument().defaultFont() fontName = globalref.miscOptions['OutputFont'] if fontName: self.defaultFont.fromString(fontName) if self.useDefaultFont: self.mainFont = self.defaultFont def adjustSpacing(self): """Adjust line spacing & indent size based on font & indent factor. """ self.lineSpacing = QFontMetrics(self.mainFont, self.printer).lineSpacing() self.indentSize = self.indentFactor * self.lineSpacing def fileData(self): """Return a dictionary of non-default settings for storage. """ data = {} if not self.drawLines: data['printlines'] = False if not self.widowControl: data['printwidowcontrol'] = False if self.indentFactor != 2.0: data['printindentfactor'] = self.indentFactor pageSizeId = self.pageLayout.pageSize().id() if pageSizeId == QPageSize.PageSizeId.Custom: paperWidth, paperHeight = self.roundedPaperSize() data['printpaperwidth'] = paperWidth data['printpaperheight'] = paperHeight elif pageSizeId != QPageSize.PageSizeId.Letter: data['printpapersize'] = self.paperSizeName(pageSizeId) if self.pageLayout.orientation() != QPageLayout.Orientation.Portrait: data['printportrait'] = False if self.roundedMargins() != (_defaultMargin,) * 4: data['printmargins'] = list(self.roundedMargins()) if self.headerMargin != _defaultHeaderPos: data['printheadermargin'] = self.headerMargin if self.footerMargin != _defaultHeaderPos: data['printfootermargin'] = self.footerMargin if self.numColumns > 1: data['printnumcolumns'] = self.numColumns if self.columnSpacing != _defaultColumnSpace: data['printcolumnspace'] = self.columnSpacing if self.headerText: data['printheadertext'] = self.headerText if self.footerText: data['printfootertext'] = self.footerText if not self.useDefaultFont: data['printfont'] = self.mainFont.toString() return data def readData(self, data): """Restore saved settings from a dictionary. Arguments: data -- a dictionary of stored non-default settings """ self.setDefaults() # necessary for undo/redo self.drawLines = data.get('printlines', True) self.widowControl = data.get('printwidowcontrol', True) self.indentFactor = data.get('printindentfactor', 2.0) if 'printpapersize' in data: self.pageLayout.setPageSize(QPageSize(getattr(QPageSize.PageSizeId, data['printpapersize']))) self.pageLayout.setMargins(QMarginsF(*(_defaultMargin,) * 4)) if 'printpaperwidth' in data and 'printpaperheight' in data: width = data['printpaperwidth'] height = data['printpaperheight'] self.pageLayout.setPageSize(QPageSize(QSizeF(width, height), QPageSize.Unit.Inch)) self.pageLayout.setMargins(QMarginsF(*(_defaultMargin,) * 4)) if not data.get('printportrait', True): self.pageLayout.setOrientation(QPageLayout.Orientation.Landscape) if 'printmargins' in data: margins = data['printmargins'] self.pageLayout.setMargins(QMarginsF(*margins)) self.headerMargin = data.get('printheadermargin', _defaultHeaderPos) self.footerMargin = data.get('printfootermargin', _defaultHeaderPos) self.numColumns = data.get('printnumcolumns', 1) self.columnSpacing = data.get('printcolumnspace', _defaultColumnSpace) self.headerText = data.get('printheadertext', '') self.footerText = data.get('printfootertext', '') if 'printfont' in data: self.useDefaultFont = False self.mainFont.fromString(data['printfont']) self.adjustSpacing() def roundedMargins(self): """Return a tuple of rounded page margins in inches. Rounds to nearest .01" to avoid Qt unit conversion artifacts. """ margins = self.pageLayout.margins(QPageLayout.Unit.Inch) return tuple(round(margin, 2) for margin in (margins.left(), margins.top(), margins.right(), margins.bottom())) def roundedPaperSize(self): """Return a tuple of rounded paper width and height. Rounds to nearest .01" to avoid Qt unit conversion artifacts. """ size = self.pageLayout.fullRect(QPageLayout.Unit.Inch) return (round(size.width(), 2), round(size.height(), 2)) def paperSizeName(self, sizeId=None): """Return a QPageSize attribute name matching the paper size ID. Arguments: sizeId -- the Qt size ID, if None, use current size """ if sizeId == None: sizeId = self.pageLayout.pageSize().id() matches = [] for name, num in vars(QPageSize.PageSizeId).items(): if num == sizeId: matches.append(name) if not matches: return 'Custom' if len(matches) > 1: text = QPageSize(sizeId).name().split(None, 1)[0] for name in matches: if name == text: return name return matches[0] def setupData(self): """Load data to be printed and set page info. """ if self.printWhat == PrintScope.entireTree: selSpots = self.localControl.structure.rootSpots() else: selSpots = (self.localControl.currentSelectionModel(). selectedSpots()) if not selSpots: selSpots = self.localControl.structure.rootSpots() self.outputGroup = treeoutput.OutputGroup(selSpots, self.includeRoot, self.printWhat != PrintScope.selectNode, self.openOnly) self.paginate() def paginate(self): """Define the pages and locations of output items and set page range. """ pageNum = 1 columnNum = 0 pagePos = 0 itemSplit = False self.checkPageLayout() heightAvail = (self.pageLayout.paintRect().height() * self.printer.logicalDpiY()) columnSpacing = int(self.columnSpacing * self.printer.logicalDpiX()) widthAvail = ((self.pageLayout.paintRect().width() * self.printer.logicalDpiX() - columnSpacing * (self.numColumns - 1)) // self.numColumns) newGroup = treeoutput.OutputGroup([]) while self.outputGroup: item = self.outputGroup.pop(0) widthRemain = widthAvail - item.level * self.indentSize if pagePos != 0 and (newGroup[-1].addSpace or item.addSpace): pagePos += self.lineSpacing if item.siblingPrefix: siblings = treeoutput.OutputGroup([]) siblings.append(item) while True: item = siblings.combineLines() item.setDocHeight(self.printer, widthRemain, self.mainFont, True) if pagePos + item.height > heightAvail: self.outputGroup.insert(0, siblings.pop()) item = (siblings.combineLines() if siblings else None) break if (self.outputGroup and item.level == self.outputGroup[0].level and item.equalPrefix(self.outputGroup[0])): siblings.append(self.outputGroup.pop(0)) else: break if item: item.setDocHeight(self.printer, widthRemain, self.mainFont, True) if item.height > heightAvail and not itemSplit: item, newItem = item.splitDocHeight(heightAvail - pagePos, heightAvail, self.printer, widthRemain, self.mainFont) if newItem: self.outputGroup.insert(0, newItem) itemSplit = True if item and (pagePos + item.height <= heightAvail or pagePos == 0): item.pageNum = pageNum item.columnNum = columnNum item.pagePos = pagePos newGroup.append(item) pagePos += item.height else: if columnNum + 1 < self.numColumns: columnNum += 1 else: pageNum += 1 columnNum = 0 pagePos = 0 itemSplit = False if item: self.outputGroup.insert(0, item) if self.widowControl and not item.siblingPrefix: moveItems = [] moveHeight = 0 level = item.level while (newGroup and not newGroup[-1].siblingPrefix and newGroup[-1].level == level - 1 and ((newGroup[-1].pageNum == pageNum - 1 and newGroup[-1].columnNum == columnNum) or (newGroup[-1].pageNum == pageNum and newGroup[-1].columnNum == columnNum - 1))): moveItems.insert(0, newGroup.pop()) moveHeight += moveItems[0].height level -= 1 if (moveItems and newGroup and moveHeight < (heightAvail // 5)): self.outputGroup[0:0] = moveItems else: newGroup.extend(moveItems) self.outputGroup = newGroup self.outputGroup.loadFamilyRefs() self.printer.setFromTo(1, pageNum) def checkPageLayout(self): """Check and set the page layout on the current printer. Verify that the layout settings match the printer, adjust if required. """ if not self.printer.setPageLayout(self.pageLayout): tempPrinter = QPrinter() tempPageLayout = tempPrinter.pageLayout() tempPageLayout.setUnits(QPageLayout.Unit.Inch) pageSizeIssue = False defaultPageSize = tempPageLayout.pageSize() tempPageLayout.setPageSize(self.pageLayout.pageSize()) if not tempPrinter.setPageLayout(tempPageLayout): pageSizeIssue = True tempPageLayout.setPageSize(defaultPageSize) marginIssue = not (tempPageLayout.setMargins(self.pageLayout. margins()) and tempPrinter.setPageLayout(tempPageLayout)) if marginIssue: margin = 0.1 while True: if (tempPageLayout.setMargins(QMarginsF(*(margin,) * 4)) and tempPrinter.setPageLayout(tempPageLayout)): break margin += 0.1 newMargins = [] for oldMargin in self.roundedMargins(): newMargins.append(oldMargin if oldMargin >= margin else margin) tempPageLayout.setMargins(QMarginsF(*newMargins)) tempPageLayout.setOrientation(self.pageLayout.orientation()) self.printer.setPageLayout(tempPageLayout) if not pageSizeIssue and not marginIssue: return if pageSizeIssue and marginIssue: msg = _('Warning: Page size and margin settings unsupported ' 'on current printer.\nSave page adjustments?') elif pageSizeIssue: msg = _('Warning: Page size setting unsupported ' 'on current printer.\nSave adjustment?') else: msg = _('Warning: Margin settings unsupported ' 'on current printer.\nSave adjustments?') ans = QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', msg, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.Yes) if ans == QMessageBox.StandardButton.Yes: self.pageLayout = tempPageLayout def paintData(self, printer): """Paint data to be printed to the printer. """ pageNum = 1 try: maxPageNum = self.outputGroup[-1].pageNum except IndexError: # printing empty branch maxPageNum = 1 if self.printer.printRange() != QPrinter.PrintRange.AllPages: pageNum = self.printer.fromPage() maxPageNum = self.printer.toPage() painter = QPainter() if not painter.begin(self.printer): QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error initializing printer')) QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) while True: self.paintPage(pageNum, painter) if pageNum == maxPageNum: QApplication.restoreOverrideCursor() return pageNum += 1 self.printer.newPage() def paintPage(self, pageNum, painter): """Paint data for the given page to the printer. Arguments: pageNum -- the page number to be printed painter -- the painter for this print job """ paintContext = QAbstractTextDocumentLayout.PaintContext() # set context text color to black to wrok with dark app themes paintContext.palette = QPalette() paintContext.palette.setColor(QPalette.ColorRole.Text, Qt.GlobalColor.black) try: totalNumPages = self.outputGroup[-1].pageNum except IndexError: # printing empty branch totalNumPages = 1 headerDoc = self.headerFooterDoc(True, pageNum, totalNumPages) if headerDoc: layout = headerDoc.documentLayout() layout.setPaintDevice(self.printer) headerDoc.setTextWidth(self.pageLayout.paintRect().width() * self.printer.logicalDpiX()) painter.save() # set a pen as a workaround to initialize color with a dark theme. pen = painter.pen() pen.setWidth(6) painter.setPen(pen) topMargin = self.pageLayout.margins(QPageLayout.Unit.Inch).top() headerDelta = ((self.headerMargin - topMargin) * self.printer.logicalDpiX()) painter.translate(0, int(headerDelta)) layout.draw(painter, paintContext) painter.restore() painter.save() columnSpacing = int(self.columnSpacing * self.printer.logicalDpiX()) columnDelta = ((self.pageLayout.paintRect().width() * self.printer.logicalDpiX() - columnSpacing * (self.numColumns - 1)) / self.numColumns) + columnSpacing for columnNum in range(self.numColumns): if columnNum > 0: painter.translate(columnDelta, 0) self.paintColumn(pageNum, columnNum, painter, paintContext) painter.restore() footerDoc = self.headerFooterDoc(False, pageNum, totalNumPages) if footerDoc: layout = footerDoc.documentLayout() layout.setPaintDevice(self.printer) footerDoc.setTextWidth(self.pageLayout.paintRect().width() * self.printer.logicalDpiX()) painter.save() bottomMargin = self.pageLayout.margins(QPageLayout. Unit.Inch).bottom() footerDelta = ((bottomMargin - self.footerMargin) * self.printer.logicalDpiX()) painter.translate(0, self.pageLayout.paintRect().height() * self.printer.logicalDpiX() + int(footerDelta) - self.lineSpacing) layout.draw(painter, paintContext) painter.restore() def paintColumn(self, pageNum, columnNum, painter, paintContext): """Paint data for the given column to the printer. Arguments: pageNum -- the page number to be printed columnNum -- the column number to be printed painter -- the painter for this print job """ columnItems = [item for item in self.outputGroup if item.pageNum == pageNum and item.columnNum == columnNum] for item in columnItems: layout = item.doc.documentLayout() painter.save() # set a pen as a workaround to initialize color with a dark theme. pen = painter.pen() pen.setWidth(6) painter.setPen(pen) painter.translate(item.level * self.indentSize, item.pagePos) layout.draw(painter, paintContext) painter.restore() if self.drawLines: self.addPrintLines(pageNum, columnNum, columnItems, painter) def addPrintLines(self, pageNum, columnNum, columnItems, painter): """Paint lines between parent and child items on the page. Arguments: pageNum -- the page number to be printed columnNum -- the column number to be printed columnItems -- a list of items in this column painter -- the painter for this print job """ parentsDrawn = set() horizOffset = self.indentSize // 2 vertOffset = self.lineSpacing // 2 heightAvail = (self.pageLayout.paintRect().height() * self.printer.logicalDpiY()) painter.save() pen = painter.pen() pen.setWidth(6) painter.setPen(pen) for item in columnItems: if item.level > 0: indent = item.level * self.indentSize vertPos = item.pagePos + vertOffset painter.drawLine(int(indent - horizOffset), int(vertPos), int(indent - self.lineSpacing // 4), int(vertPos)) parent = item.parentItem while parent: if parent in parentsDrawn: break lineStart = 0 lineEnd = heightAvail if (parent.pageNum == pageNum and parent.columnNum == columnNum): lineStart = parent.pagePos + parent.height if (parent.lastChildItem.pageNum == pageNum and parent.lastChildItem.columnNum == columnNum): lineEnd = parent.lastChildItem.pagePos + vertOffset if (parent.lastChildItem.pageNum > pageNum or (parent.lastChildItem.pageNum == pageNum and parent.lastChildItem.columnNum >= columnNum)): horizPos = ((parent.level + 1) * self.indentSize - horizOffset) painter.drawLine(int(horizPos), int(lineStart), int(horizPos), int(lineEnd)) parentsDrawn.add(parent) parent = parent.parentItem painter.restore() def formatHeaderFooter(self, header=True, pageNum=1, numPages=1): """Return an HTML table formatted header or footer. Return an empty string if no header/footer is defined. Arguments: header -- return header if True, footer if false """ if header: textParts = printdialogs.splitHeaderFooter(self.headerText) else: textParts = printdialogs.splitHeaderFooter(self.footerText) if not textParts: return '' fileInfoFormat = self.localControl.structure.treeFormats.fileInfoFormat fileInfoNode = self.localControl.structure.fileInfoNode fileInfoFormat.updateFileInfo(self.localControl.filePathObj, fileInfoNode) fileInfoNode.data[fileInfoFormat.pageNumFieldName] = repr(pageNum) fileInfoNode.data[fileInfoFormat.numPagesFieldName] = repr(numPages) fileInfoFormat.changeOutputLines(textParts, keepBlanks=True) textParts = fileInfoFormat.formatOutput(fileInfoNode, keepBlanks=True) alignments = ('left', 'center', 'right') result = [''] for text, align in zip(textParts, alignments): if text: result.append(''.format(align, text)) if len(result) > 1: result.append('
    {1}
    ') return '\n'.join(result) return '' def headerFooterDoc(self, header=True, pageNum=1, numPages=1): """Return a text document for the header or footer. Return None if no header/footer is defined. Arguments: header -- return header if True, footer if false """ text = self.formatHeaderFooter(header, pageNum, numPages) if text: doc = QTextDocument() doc.setHtml(text) doc.setDefaultFont(self.mainFont) frameFormat = doc.rootFrame().frameFormat() frameFormat.setBorder(0) frameFormat.setMargin(0) frameFormat.setPadding(0) doc.rootFrame().setFrameFormat(frameFormat) return doc return None def printSetup(self): """Show a dialog to set margins, page size and other printing options. """ setupDialog = printdialogs.PrintSetupDialog(self, True, QApplication. activeWindow()) setupDialog.exec() def printPreview(self): """Show a preview of printing results. """ self.setupData() previewDialog = printdialogs.PrintPreviewDialog(self,QApplication. activeWindow()) previewDialog.previewWidget.paintRequested.connect(self.paintData) if globalref.genOptions['SaveWindowGeom']: previewDialog.restoreDialogGeom() previewDialog.exec() def filePrint(self): """Show dialog and print tree output based on current options. """ self.printer.setOutputFormat(QPrinter.OutputFormat.NativeFormat) self.setupData() printDialog = QPrintDialog(self.printer, QApplication.activeWindow()) if printDialog.exec() == QDialog.DialogCode.Accepted: self.paintData(self.printer) def filePrintPdf(self): """Export to a PDF file with current options. """ filters = ';;'.join((globalref.fileFilters['pdf'], globalref.fileFilters['all'])) defaultFilePath = str(globalref.mainControl.defaultPathObj()) defaultFilePath = os.path.splitext(defaultFilePath)[0] if os.path.basename(defaultFilePath): defaultFilePath = '{0}.{1}'.format(defaultFilePath, 'pdf') filePath, selectFilter = QFileDialog.getSaveFileName(QApplication. activeWindow(), _('TreeLine - Export PDF'), defaultFilePath, filters) if not filePath: return if not os.path.splitext(filePath)[1]: filePath = '{0}.{1}'.format(filePath, 'pdf') origFormat = self.printer.outputFormat() self.printer.setOutputFormat(QPrinter.OutputFormat.PdfFormat) self.printer.setOutputFileName(filePath) self.adjustSpacing() self.setupData() self.paintData(self.printer) self.printer.setOutputFormat(origFormat) self.printer.setOutputFileName('') self.adjustSpacing() TreeLine-3.2.1/source/printdialogs.py000066400000000000000000001616371506556630100176220ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # printdialogs.py, provides print preview and print settings dialogs # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import collections from PyQt6.QtCore import (QMarginsF, QPoint, QRect, QSize, QSizeF, Qt, pyqtSignal) from PyQt6.QtGui import (QAction, QFontDatabase, QFontInfo, QFontMetrics, QIntValidator, QPageLayout, QPageSize) from PyQt6.QtWidgets import (QAbstractItemView, QButtonGroup, QCheckBox, QComboBox, QDialog, QDoubleSpinBox, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QListWidget, QMenu, QMessageBox, QPushButton, QRadioButton, QSpinBox, QTabWidget, QToolBar, QVBoxLayout, QWidget) from PyQt6.QtPrintSupport import (QPrintPreviewWidget, QPrinter, QPrinterInfo) import printdata import configdialog import treeformats import undo import globalref class PrintPreviewDialog(QDialog): """Dialog for print previews. Similar to QPrintPreviewDialog but calls a custom page setup dialog. """ def __init__(self, printData, parent=None): """Create the print preview dialog. Arguments: printData -- the PrintData object parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Print Preview')) self.printData = printData topLayout = QVBoxLayout(self) self.setLayout(topLayout) toolBar = QToolBar(self) topLayout.addWidget(toolBar) self.previewWidget = QPrintPreviewWidget(printData.printer, self) topLayout.addWidget(self.previewWidget) self.previewWidget.previewChanged.connect(self.updateControls) self.zoomWidthAct = QAction(_('Fit Width'), self, checkable=True) icon = globalref.toolIcons.getIcon('printpreviewzoomwidth') if icon: self.zoomWidthAct.setIcon(icon) self.zoomWidthAct.triggered.connect(self.zoomWidth) toolBar.addAction(self.zoomWidthAct) self.zoomAllAct = QAction(_('Fit Page'), self, checkable=True) icon = globalref.toolIcons.getIcon('printpreviewzoomall') if icon: self.zoomAllAct.setIcon(icon) self.zoomAllAct.triggered.connect(self.zoomAll) toolBar.addAction(self.zoomAllAct) toolBar.addSeparator() self.zoomCombo = QComboBox(self) self.zoomCombo.setEditable(True) self.zoomCombo.setInsertPolicy(QComboBox.InsertPolicy.NoInsert) self.zoomCombo.addItems([' 12%', ' 25%', ' 50%', ' 75%', ' 100%', ' 125%', ' 150%', ' 200%', ' 400%', ' 800%']) self.zoomCombo.currentTextChanged.connect(self.zoomToValue) self.zoomCombo.lineEdit().returnPressed.connect(self.zoomToValue) toolBar.addWidget(self.zoomCombo) zoomInAct = QAction(_('Zoom In'), self) icon = globalref.toolIcons.getIcon('printpreviewzoomin') if icon: zoomInAct.setIcon(icon) zoomInAct.triggered.connect(self.zoomIn) toolBar.addAction(zoomInAct) zoomOutAct = QAction(_('Zoom Out'), self) icon = globalref.toolIcons.getIcon('printpreviewzoomout') if icon: zoomOutAct.setIcon(icon) zoomOutAct.triggered.connect(self.zoomOut) toolBar.addAction(zoomOutAct) toolBar.addSeparator() self.previousAct = QAction(_('Previous Page'), self) icon = globalref.toolIcons.getIcon('printpreviewprevious') if icon: self.previousAct.setIcon(icon) self.previousAct.triggered.connect(self.previousPage) toolBar.addAction(self.previousAct) self.pageNumEdit = QLineEdit(self) self.pageNumEdit.setAlignment(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter) width = QFontMetrics(self.pageNumEdit.font()).size(Qt.TextFlag. TextSingleLine, '0000').width() self.pageNumEdit.setMaximumWidth(width) self.pageNumEdit.returnPressed.connect(self.setPageNum) toolBar.addWidget(self.pageNumEdit) self.maxPageLabel = QLabel(' / 000 ', self) toolBar.addWidget(self.maxPageLabel) self.nextAct = QAction(_('Next Page'), self) icon = globalref.toolIcons.getIcon('printpreviewnext') if icon: self.nextAct.setIcon(icon) self.nextAct.triggered.connect(self.nextPage) toolBar.addAction(self.nextAct) toolBar.addSeparator() self.onePageAct = QAction(_('Single Page'), self, checkable=True) icon = globalref.toolIcons.getIcon('printpreviewsingle') if icon: self.onePageAct.setIcon(icon) self.onePageAct.triggered.connect(self.previewWidget. setSinglePageViewMode) toolBar.addAction(self.onePageAct) self.twoPageAct = QAction(_('Facing Pages'), self, checkable=True) icon = globalref.toolIcons.getIcon('printpreviewdouble') if icon: self.twoPageAct.setIcon(icon) self.twoPageAct.triggered.connect(self.previewWidget. setFacingPagesViewMode) toolBar.addAction(self.twoPageAct) toolBar.addSeparator() pageSetupAct = QAction(_('Print Setup'), self) icon = globalref.toolIcons.getIcon('fileprintsetup') if icon: pageSetupAct.setIcon(icon) pageSetupAct.triggered.connect(self.printSetup) toolBar.addAction(pageSetupAct) filePrintAct = QAction(_('Print'), self) icon = globalref.toolIcons.getIcon('fileprint') if icon: filePrintAct.setIcon(icon) filePrintAct.triggered.connect(self.filePrint) toolBar.addAction(filePrintAct) def updateControls(self): """Update control availability and status based on a change signal. """ self.zoomWidthAct.setChecked(self.previewWidget.zoomMode() == QPrintPreviewWidget.ZoomMode.FitToWidth) self.zoomAllAct.setChecked(self.previewWidget.zoomMode() == QPrintPreviewWidget.ZoomMode.FitInView) zoom = self.previewWidget.zoomFactor() * 100 self.zoomCombo.setEditText('{0:4.0f}%'.format(zoom)) self.previousAct.setEnabled(self.previewWidget.currentPage() > 1) self.nextAct.setEnabled(self.previewWidget.currentPage() < self.previewWidget.pageCount()) self.pageNumEdit.setText(str(self.previewWidget.currentPage())) self.maxPageLabel.setText(' / {0} '.format(self.previewWidget. pageCount())) self.onePageAct.setChecked(self.previewWidget.viewMode() == QPrintPreviewWidget.ViewMode.SinglePageView) self.twoPageAct.setChecked(self.previewWidget.viewMode() == QPrintPreviewWidget.ViewMode. FacingPagesView) def zoomWidth(self, checked=True): """Set the fit to width zoom mode if checked. Arguments: checked -- set this mode if True """ if checked: self.previewWidget.setZoomMode(QPrintPreviewWidget.ZoomMode. FitToWidth) else: self.previewWidget.setZoomMode(QPrintPreviewWidget.ZoomMode. CustomZoom) self.updateControls() def zoomAll(self, checked=True): """Set the fit in view zoom mode if checked. Arguments: checked -- set this mode if True """ if checked: self.previewWidget.setZoomMode(QPrintPreviewWidget.ZoomMode.FitInView) else: self.previewWidget.setZoomMode(QPrintPreviewWidget.ZoomMode. CustomZoom) self.updateControls() def zoomToValue(self, factorStr=''): """Zoom to the given combo box string value. Arguments: factorStr -- the zoom factor as a string, often with a % suffix """ if not factorStr: factorStr = self.zoomCombo.lineEdit().text() try: factor = float(factorStr.strip(' %')) / 100 self.previewWidget.setZoomFactor(factor) except ValueError: pass self.updateControls() def zoomIn(self): """Increase the zoom level by an increment. """ self.previewWidget.zoomIn() self.updateControls() def zoomOut(self): """Decrease the zoom level by an increment. """ self.previewWidget.zoomOut() self.updateControls() def previousPage(self): """Go to the previous page of the preview. """ self.previewWidget.setCurrentPage(self.previewWidget.currentPage() - 1) self.updateControls() def nextPage(self): """Go to the next page of the preview. """ self.previewWidget.setCurrentPage(self.previewWidget.currentPage() + 1) self.updateControls() def setPageNum(self): """Go to a page number from the line editor based on a signal. """ try: self.previewWidget.setCurrentPage(int(self.pageNumEdit.text())) except ValueError: pass self.updateControls() def printSetup(self): """Show a dialog to set margins, page size and other printing options. """ setupDialog = PrintSetupDialog(self.printData, False, self) if setupDialog.exec() == QDialog.DialogCode.Accepted: self.printData.setupData() self.previewWidget.updatePreview() def filePrint(self): """Show dialog and print tree output based on current options. """ self.close() if (self.printData.printer.outputFormat() == QPrinter.OutputFormat.NativeFormat): self.printData.filePrint() else: self.printData.filePrintPdf() def sizeHint(self): """Return a larger default height. """ size = super().sizeHint() size.setHeight(600) return size def restoreDialogGeom(self): """Restore dialog window geometry from history options. """ rect = QRect(globalref.histOptions['PrintPrevXPos'], globalref.histOptions['PrintPrevYPos'], globalref.histOptions['PrintPrevXSize'], globalref.histOptions['PrintPrevYSize']) if rect.height() and rect.width(): self.setGeometry(rect) def saveDialogGeom(self): """Savedialog window geometry to history options. """ globalref.histOptions.changeValue('PrintPrevXSize', self.width()) globalref.histOptions.changeValue('PrintPrevYSize', self.height()) globalref.histOptions.changeValue('PrintPrevXPos', self.geometry().x()) globalref.histOptions.changeValue('PrintPrevYPos', self.geometry().y()) def closeEvent(self, event): """Save dialog geometry at close. Arguments: event -- the close event """ if globalref.genOptions['SaveWindowGeom']: self.saveDialogGeom() class PrintSetupDialog(QDialog): """Base dialog for setting the print configuration. Pushes most options to the PrintData class. """ def __init__(self, printData, showExtraButtons=True, parent=None): """Create the printing setup dialog. Arguments: printData -- a reference to the PrintData class showExtraButtons -- add print preview and print shortcut buttons parent -- the parent window """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Printing Setup')) self.printData = printData topLayout = QVBoxLayout(self) self.setLayout(topLayout) tabs = QTabWidget() topLayout.addWidget(tabs) generalPage = GeneralPage(self.printData) tabs.addTab(generalPage, _('&General Options')) pageSetupPage = PageSetupPage(self.printData, generalPage.currentPrinterName) tabs.addTab(pageSetupPage, _('Page &Setup')) fontPage = FontPage(self.printData) tabs.addTab(fontPage, _('&Font Selection')) headerPage = HeaderPage(self.printData) tabs.addTab(headerPage, _('&Header/Footer')) generalPage.printerChanged.connect(pageSetupPage.changePrinter) self.tabPages = [generalPage, pageSetupPage, fontPage, headerPage] ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() if showExtraButtons: previewButton = QPushButton(_('Print Pre&view...')) ctrlLayout.addWidget(previewButton) previewButton.clicked.connect(self.preview) printButton = QPushButton(_('&Print...')) ctrlLayout.addWidget(printButton) printButton.clicked.connect(self.quickPrint) okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) def quickPrint(self): """Accept this dialog and go to print dialog. """ self.accept() if (self.printData.printer.outputFormat() == QPrinter.OutputFormat.NativeFormat): self.printData.filePrint() else: self.printData.filePrintPdf() def preview(self): """Accept this dialog and go to print preview dialog. """ self.accept() self.printData.printPreview() def accept(self): """Store results before closing dialog. """ if not self.tabPages[1].checkValid(): QMessageBox.warning(self, 'TreeLine', _('Error: Page size or margins are invalid')) return changed = False control = self.printData.localControl undoObj = undo.StateSettingUndo(control.structure.undoList, self.printData.fileData, self.printData.readData) for page in self.tabPages: if page.saveChanges(): changed = True if changed: self.printData.adjustSpacing() control.setModified() else: control.structure.undoList.removeLastUndo(undoObj) super().accept() _pdfPrinterName = _('TreeLine PDF Printer') class GeneralPage(QWidget): """Dialog page for misc. print options. """ printerChanged = pyqtSignal(str) def __init__(self, printData, parent=None): """Create the general settings page. Arguments: printData -- a reference to the PrintData class parent -- the parent dialog """ super().__init__(parent) self.printData = printData self.printerList = QPrinterInfo.availablePrinterNames() self.printerList.insert(0, _pdfPrinterName) self.currentPrinterName = self.printData.printer.printerName() if not self.currentPrinterName: self.currentPrinterName = _pdfPrinterName topLayout = QHBoxLayout(self) self.setLayout(topLayout) leftLayout = QVBoxLayout() topLayout.addLayout(leftLayout) whatGroupBox = QGroupBox(_('What to print')) leftLayout.addWidget(whatGroupBox) whatLayout = QVBoxLayout(whatGroupBox) self.whatButtons = QButtonGroup(self) treeButton = QRadioButton(_('&Entire tree')) self.whatButtons.addButton(treeButton, printdata.PrintScope.entireTree) whatLayout.addWidget(treeButton) branchButton = QRadioButton(_('Selected &branches')) self.whatButtons.addButton(branchButton, printdata.PrintScope.selectBranch) whatLayout.addWidget(branchButton) nodeButton = QRadioButton(_('Selected &nodes')) self.whatButtons.addButton(nodeButton, printdata.PrintScope.selectNode) whatLayout.addWidget(nodeButton) self.whatButtons.button(self.printData.printWhat).setChecked(True) self.whatButtons.buttonClicked.connect(self.updateCmdAvail) includeBox = QGroupBox(_('Included Nodes')) leftLayout.addWidget(includeBox) includeLayout = QVBoxLayout(includeBox) self.rootButton = QCheckBox(_('&Include root node')) includeLayout.addWidget(self.rootButton) self.rootButton.setChecked(self.printData.includeRoot) self.openOnlyButton = QCheckBox(_('Onl&y open node children')) includeLayout.addWidget(self.openOnlyButton) self.openOnlyButton.setChecked(self.printData.openOnly) leftLayout.addStretch() rightLayout = QVBoxLayout() topLayout.addLayout(rightLayout) printerBox = QGroupBox(_('Select &Printer')) rightLayout.addWidget(printerBox) printerLayout = QVBoxLayout(printerBox) printerCombo = QComboBox() printerLayout.addWidget(printerCombo) printerCombo.addItems(self.printerList) printerCombo.setCurrentIndex(self.printerList.index(self. currentPrinterName)) printerCombo.currentIndexChanged.connect(self.changePrinter) featureBox = QGroupBox(_('Features')) rightLayout.addWidget(featureBox) featureLayout = QVBoxLayout(featureBox) self.linesButton = QCheckBox(_('&Draw lines to children')) featureLayout.addWidget(self.linesButton) self.linesButton.setChecked(self.printData.drawLines) self.widowButton = QCheckBox(_('&Keep first child with parent')) featureLayout.addWidget(self.widowButton) self.widowButton.setChecked(self.printData.widowControl) indentBox = QGroupBox(_('Indent')) rightLayout.addWidget(indentBox) indentLayout = QHBoxLayout(indentBox) indentLabel = QLabel(_('Indent Offse&t\n(line height units)')) indentLayout.addWidget(indentLabel) self.indentSpin = QDoubleSpinBox() indentLayout.addWidget(self.indentSpin) indentLabel.setBuddy(self.indentSpin) self.indentSpin.setMinimum(0.5) self.indentSpin.setSingleStep(0.5) self.indentSpin.setDecimals(1) self.indentSpin.setValue(self.printData.indentFactor) rightLayout.addStretch() self.updateCmdAvail() def updateCmdAvail(self): """Update options available based on print what settings. """ if self.whatButtons.checkedId() == printdata.PrintScope.selectNode: self.rootButton.setChecked(True) self.rootButton.setEnabled(False) self.openOnlyButton.setChecked(False) self.openOnlyButton.setEnabled(False) else: self.rootButton.setEnabled(True) self.openOnlyButton.setEnabled(True) def changePrinter(self, printerNum): """Change the current printer based on a combo box signal. Arguments: printerNum -- the printer number from the combo box """ self.currentPrinterName = self.printerList[printerNum] self.printerChanged.emit(self.currentPrinterName) def saveChanges(self): """Update print data with current dialog settings. Return True if saved settings have changed, False otherwise. """ self.printData.printWhat = self.whatButtons.checkedId() self.printData.includeRoot = self.rootButton.isChecked() self.printData.openOnly = self.openOnlyButton.isChecked() if self.currentPrinterName != _pdfPrinterName: self.printData.printer.setPrinterName(self.currentPrinterName) else: self.printData.printer.setPrinterName('') changed = False if self.printData.drawLines != self.linesButton.isChecked(): self.printData.drawLines = self.linesButton.isChecked() changed = True if self.printData.widowControl != self.widowButton.isChecked(): self.printData.widowControl = self.widowButton.isChecked() changed = True if self.printData.indentFactor != self.indentSpin.value(): self.printData.indentFactor = self.indentSpin.value() changed = True return changed _paperSizes = collections.OrderedDict([('Letter', _('Letter (8.5 x 11 in.)')), ('Legal', _('Legal (8.5 x 14 in.)'),), ('Tabloid', _('Tabloid (11 x 17 in.)')), ('A3', _('A3 (279 x 420 mm)')), ('A4', _('A4 (210 x 297 mm)')), ('A5', _('A5 (148 x 210 mm)')), ('Custom', _('Custom Size'))]) _units = collections.OrderedDict([('in', _('Inches (in)')), ('mm', _('Millimeters (mm)')), ('cm', _('Centimeters (cm)'))]) _unitValues = {'in': 1.0, 'cm': 2.54, 'mm': 25.4} _unitDecimals = {'in': 2, 'cm': 1, 'mm': 0} class PageSetupPage(QWidget): """Dialog page for page setup options. """ def __init__(self, printData, currentPrinterName, parent=None): """Create the page setup settings page. Arguments: printData -- a reference to the PrintData class currentPrinterName -- the selected printer for validation parent -- the parent dialog """ super().__init__(parent) self.printData = printData self.currentPrinterName = currentPrinterName topLayout = QHBoxLayout(self) self.setLayout(topLayout) leftLayout = QVBoxLayout() topLayout.addLayout(leftLayout) unitsBox = QGroupBox(_('&Units')) leftLayout.addWidget(unitsBox) unitsLayout = QVBoxLayout(unitsBox) unitsCombo = QComboBox() unitsLayout.addWidget(unitsCombo) unitsCombo.addItems(list(_units.values())) self.currentUnit = globalref.miscOptions['PrintUnits'] if self.currentUnit not in _units: self.currentUnit = 'in' unitsCombo.setCurrentIndex(list(_units.keys()).index(self.currentUnit)) unitsCombo.currentIndexChanged.connect(self.changeUnits) paperSizeBox = QGroupBox(_('Paper &Size')) leftLayout.addWidget(paperSizeBox) paperSizeLayout = QGridLayout(paperSizeBox) spacing = paperSizeLayout.spacing() paperSizeLayout.setVerticalSpacing(0) paperSizeLayout.setRowMinimumHeight(1, spacing) paperSizeCombo = QComboBox() paperSizeLayout.addWidget(paperSizeCombo, 0, 0, 1, 2) paperSizeCombo.addItems(list(_paperSizes.values())) self.currentPaperSize = self.printData.paperSizeName() if self.currentPaperSize not in _paperSizes: self.currentPaperSize = 'Custom' paperSizeCombo.setCurrentIndex(list(_paperSizes.keys()). index(self.currentPaperSize)) paperSizeCombo.currentIndexChanged.connect(self.changePaper) widthLabel = QLabel(_('&Width:')) paperSizeLayout.addWidget(widthLabel, 2, 0) self.paperWidthSpin = UnitSpinBox(self.currentUnit) paperSizeLayout.addWidget(self.paperWidthSpin, 3, 0) widthLabel.setBuddy(self.paperWidthSpin) paperWidth, paperHeight = self.printData.roundedPaperSize() self.paperWidthSpin.setInchValue(paperWidth) heightlabel = QLabel(_('Height:')) paperSizeLayout.addWidget(heightlabel, 2, 1) self.paperHeightSpin = UnitSpinBox(self.currentUnit) paperSizeLayout.addWidget(self.paperHeightSpin, 3, 1) heightlabel.setBuddy(self.paperHeightSpin) self.paperHeightSpin.setInchValue(paperHeight) if self.currentPaperSize != 'Custom': self.paperWidthSpin.setEnabled(False) self.paperHeightSpin.setEnabled(False) orientbox = QGroupBox(_('Orientation')) leftLayout.addWidget(orientbox) orientLayout = QVBoxLayout(orientbox) portraitButton = QRadioButton(_('Portra&it')) orientLayout.addWidget(portraitButton) landscapeButton = QRadioButton(_('Lan&dscape')) orientLayout.addWidget(landscapeButton) self.portraitOrient = (self.printData.pageLayout.orientation() == QPageLayout.Orientation.Portrait) if self.portraitOrient: portraitButton.setChecked(True) else: landscapeButton.setChecked(True) portraitButton.toggled.connect(self.changeOrient) rightLayout = QVBoxLayout() topLayout.addLayout(rightLayout) marginsBox = QGroupBox(_('Margins')) rightLayout.addWidget(marginsBox) marginsLayout = QGridLayout(marginsBox) spacing = marginsLayout.spacing() marginsLayout.setVerticalSpacing(0) marginsLayout.setRowMinimumHeight(2, spacing) marginsLayout.setRowMinimumHeight(5, spacing) leftLabel = QLabel(_('&Left:')) marginsLayout.addWidget(leftLabel, 3, 0) leftMarginSpin = UnitSpinBox(self.currentUnit) marginsLayout.addWidget(leftMarginSpin, 4, 0) leftLabel.setBuddy(leftMarginSpin) topLabel = QLabel(_('&Top:')) marginsLayout.addWidget(topLabel, 0, 1) topMarginSpin = UnitSpinBox(self.currentUnit) marginsLayout.addWidget(topMarginSpin, 1, 1) topLabel.setBuddy(topMarginSpin) rightLabel = QLabel(_('&Right:')) marginsLayout.addWidget(rightLabel, 3, 2) rightMarginSpin = UnitSpinBox(self.currentUnit) marginsLayout.addWidget(rightMarginSpin, 4, 2) rightLabel.setBuddy(rightMarginSpin) bottomLabel = QLabel(_('&Bottom:')) marginsLayout.addWidget(bottomLabel, 6, 1) bottomMarginSpin = UnitSpinBox(self.currentUnit) marginsLayout.addWidget(bottomMarginSpin, 7, 1) bottomLabel.setBuddy(bottomMarginSpin) self.marginControls = (leftMarginSpin, topMarginSpin, rightMarginSpin, bottomMarginSpin) for control, value in zip(self.marginControls, self.printData.roundedMargins()): control.setInchValue(value) headerLabel = QLabel(_('He&ader:')) marginsLayout.addWidget(headerLabel, 0, 2) self.headerMarginSpin = UnitSpinBox(self.currentUnit) marginsLayout.addWidget(self.headerMarginSpin, 1, 2) headerLabel.setBuddy(self.headerMarginSpin) self.headerMarginSpin.setInchValue(self.printData.headerMargin) footerLabel = QLabel(_('Foot&er:')) marginsLayout.addWidget(footerLabel, 6, 2) self.footerMarginSpin = UnitSpinBox(self.currentUnit) marginsLayout.addWidget(self.footerMarginSpin, 7, 2) footerLabel.setBuddy(self.footerMarginSpin) self.footerMarginSpin.setInchValue(self.printData.footerMargin) columnsBox = QGroupBox(_('Columns')) rightLayout.addWidget(columnsBox) columnLayout = QGridLayout(columnsBox) numLabel = QLabel(_('&Number of columns')) columnLayout.addWidget(numLabel, 0, 0) self.columnSpin = QSpinBox() columnLayout.addWidget(self.columnSpin, 0, 1) numLabel.setBuddy(self.columnSpin) self.columnSpin.setMinimum(1) self.columnSpin.setMaximum(9) self.columnSpin.setValue(self.printData.numColumns) spaceLabel = QLabel(_('Space between colu&mns')) columnLayout.addWidget(spaceLabel, 1, 0) self.columnSpaceSpin = UnitSpinBox(self.currentUnit) columnLayout.addWidget(self.columnSpaceSpin, 1, 1) spaceLabel.setBuddy(self.columnSpaceSpin) self.columnSpaceSpin.setInchValue(self.printData.columnSpacing) def changePrinter(self, newPrinterName): """Change the currently selected printer. Arguments: newPrinterName -- new printer selection """ self.currentPrinterName = newPrinterName def changeUnits(self, unitNum): """Change the current unit and update conversions based on a signal. Arguments: unitNum -- the unit index number from the combobox """ oldUnit = self.currentUnit self.currentUnit = list(_units.keys())[unitNum] self.paperWidthSpin.changeUnit(self.currentUnit) self.paperHeightSpin.changeUnit(self.currentUnit) for control in self.marginControls: control.changeUnit(self.currentUnit) self.headerMarginSpin.changeUnit(self.currentUnit) self.footerMarginSpin.changeUnit(self.currentUnit) self.columnSpaceSpin.changeUnit(self.currentUnit) def changePaper(self, paperNum): """Change the current paper size based on a signal. Arguments: paperNum -- the paper size index number from the combobox """ self.currentPaperSize = list(_paperSizes.keys())[paperNum] if self.currentPaperSize != 'Custom': tempPrinter = QPrinter() pageLayout = tempPrinter.pageLayout() pageLayout.setPageSize(QPageSize(getattr(QPageSize.PageSizeId, self.currentPaperSize))) if not self.portraitOrient: pageLayout.setOrientation(QPageLayout.Orientation.Landscape) paperSize = pageLayout.fullRect(QPageLayout.Unit.Inch) self.paperWidthSpin.setInchValue(round(paperSize.width(), 2)) self.paperHeightSpin.setInchValue(round(paperSize.height(), 2)) self.paperWidthSpin.setEnabled(self.currentPaperSize == 'Custom') self.paperHeightSpin.setEnabled(self.currentPaperSize == 'Custom') def changeOrient(self, isPortrait): """Change the orientation based on a signal. Arguments: isPortrait -- true if portrait orientation is selected """ self.portraitOrient = isPortrait width = self.paperWidthSpin.inchValue height = self.paperHeightSpin.inchValue if (self.portraitOrient and width > height) or (not self.portraitOrient and width < height): self.paperWidthSpin.setInchValue(height) self.paperHeightSpin.setInchValue(width) def checkValid(self): """Return True if the current page size and margins appear to be valid. """ pageWidth = self.paperWidthSpin.inchValue pageHeight = self.paperHeightSpin.inchValue if pageWidth <= 0 or pageHeight <= 0: return False margins = tuple(control.inchValue for control in self.marginControls) if (margins[0] + margins[2] >= pageWidth or margins[1] + margins[3] >= pageHeight): return False return True def saveChanges(self): """Update print data with current dialog settings. Return True if saved settings have changed, False otherwise. """ if self.currentUnit != globalref.miscOptions['PrintUnits']: globalref.miscOptions.changeValue('PrintUnits', self.currentUnit) globalref.miscOptions.writeFile() changed = False pageLayout = self.printData.pageLayout if self.currentPaperSize != 'Custom': size = getattr(QPageSize.PageSizeId, self.currentPaperSize) if size != pageLayout.pageSize().id(): pageLayout.setPageSize(QPageSize(size)) changed = True else: size = (self.paperWidthSpin.inchValue, self.paperHeightSpin.inchValue) if size != self.printData.roundedPaperSize(): pageLayout.setPageSize(QPageSize(QSizeF(*size), QPageSize.Unit.Inch)) changed = True orient = (QPageLayout.Orientation.Portrait if self.portraitOrient else QPageLayout.Orientation.Landscape) if orient != pageLayout.orientation(): pageLayout.setOrientation(orient) changed = True margins = tuple(control.inchValue for control in self.marginControls) if margins != self.printData.roundedMargins(): pageLayout.setMargins(QMarginsF(*margins)) changed = True if self.printData.headerMargin != self.headerMarginSpin.inchValue: self.printData.headerMargin = self.headerMarginSpin.inchValue changed = True if self.printData.footerMargin != self.footerMarginSpin.inchValue: self.printData.footerMargin = self.footerMarginSpin.inchValue changed = True if self.printData.numColumns != self.columnSpin.value(): self.printData.numColumns = self.columnSpin.value() changed = True if self.printData.columnSpacing != self.columnSpaceSpin.inchValue: self.printData.columnSpacing = self.columnSpaceSpin.inchValue changed = True return changed class UnitSpinBox(QDoubleSpinBox): """Spin box with unit suffix that can convert the units of its contents. Stores the value at full precision to avoid round-trip rounding errors. """ def __init__(self, unit, parent=None): """Create the unit spin box. Arguments: unit -- the original unit (abbreviated string) parent -- the parent dialog if given """ super().__init__(parent) self.unit = unit self.inchValue = 0.0 self.setupUnit() self.valueChanged.connect(self.changeValue) def setupUnit(self): """Set the suffix, decimal places and maximum based on the unit. """ self.blockSignals(True) self.setSuffix(' {0}'.format(self.unit)) decPlaces = _unitDecimals[self.unit] self.setDecimals(decPlaces) # set maximum to 5 digits total self.setMaximum((10**5 - 1) / 10**decPlaces) self.blockSignals(False) def changeUnit(self, unit): """Change current unit. Arguments: unit -- the new unit (abbreviated string) """ self.unit = unit self.setupUnit() self.setInchValue(self.inchValue) def setInchValue(self, inchValue): """Set box to given value, converted to current unit. Arguments: inchValue -- the value to set in inches """ self.inchValue = inchValue value = self.inchValue * _unitValues[self.unit] self.blockSignals(True) self.setValue(value) self.blockSignals(False) if value < 4: self.setSingleStep(0.1) elif value > 50: self.setSingleStep(10) else: self.setSingleStep(1) def changeValue(self): """Change the stored inch value based on a signal. """ self.inchValue = round(self.value() / _unitValues[self.unit], 2) class SmallListWidget(QListWidget): """ListWidget with a smaller size hint. """ def __init__(self, parent=None): """Initialize the widget. Arguments: parent -- the parent, if given """ super().__init__(parent) def sizeHint(self): """Return smaller width. """ itemHeight = self.visualItemRect(self.item(0)).height() return QSize(100, itemHeight * 3) class FontPage(QWidget): """Font selection print option dialog page. """ def __init__(self, printData, defaultLabel='', parent=None): """Create the font settings page. Arguments: printData -- a reference to the PrintData class defaultLabel -- default font label if given, o/w TreeLine output parent -- the parent dialog """ super().__init__(parent) self.printData = printData self.currentFont = self.printData.mainFont topLayout = QVBoxLayout(self) self.setLayout(topLayout) defaultBox = QGroupBox(_('Default Font')) topLayout.addWidget(defaultBox) defaultLayout = QVBoxLayout(defaultBox) if not defaultLabel: defaultLabel = _('&Use TreeLine output view font') self.defaultCheck = QCheckBox(defaultLabel) defaultLayout.addWidget(self.defaultCheck) self.defaultCheck.setChecked(self.printData.useDefaultFont) self.defaultCheck.clicked.connect(self.setFontSelectAvail) self.fontBox = QGroupBox(_('Select Font')) topLayout.addWidget(self.fontBox) fontLayout = QGridLayout(self.fontBox) spacing = fontLayout.spacing() fontLayout.setSpacing(0) label = QLabel(_('&Font')) fontLayout.addWidget(label, 0, 0) label.setIndent(2) self.familyEdit = QLineEdit() fontLayout.addWidget(self.familyEdit, 1, 0) self.familyEdit.setReadOnly(True) self.familyList = SmallListWidget() fontLayout.addWidget(self.familyList, 2, 0) label.setBuddy(self.familyList) self.familyEdit.setFocusProxy(self.familyList) fontLayout.setColumnMinimumWidth(1, spacing) families = [family for family in QFontDatabase.families()] families.sort(key=str.lower) self.familyList.addItems(families) self.familyList.currentItemChanged.connect(self.updateFamily) label = QLabel(_('Font st&yle')) fontLayout.addWidget(label, 0, 2) label.setIndent(2) self.styleEdit = QLineEdit() fontLayout.addWidget(self.styleEdit, 1, 2) self.styleEdit.setReadOnly(True) self.styleList = SmallListWidget() fontLayout.addWidget(self.styleList, 2, 2) label.setBuddy(self.styleList) self.styleEdit.setFocusProxy(self.styleList) fontLayout.setColumnMinimumWidth(3, spacing) self.styleList.currentItemChanged.connect(self.updateStyle) label = QLabel(_('Si&ze')) fontLayout.addWidget(label, 0, 4) label.setIndent(2) self.sizeEdit = QLineEdit() fontLayout.addWidget(self.sizeEdit, 1, 4) self.sizeEdit.setFocusPolicy(Qt.FocusPolicy.ClickFocus) validator = QIntValidator(1, 512, self) self.sizeEdit.setValidator(validator) self.sizeList = SmallListWidget() fontLayout.addWidget(self.sizeList, 2, 4) label.setBuddy(self.sizeList) self.sizeList.currentItemChanged.connect(self.updateSize) fontLayout.setColumnStretch(0, 30) fontLayout.setColumnStretch(2, 25) fontLayout.setColumnStretch(4, 10) sampleBox = QGroupBox(_('Sample')) topLayout.addWidget(sampleBox) sampleLayout = QVBoxLayout(sampleBox) self.sampleEdit = QLineEdit() sampleLayout.addWidget(self.sampleEdit) self.sampleEdit.setAlignment(Qt.AlignmentFlag.AlignCenter) self.sampleEdit.setText(_('AaBbCcDdEeFfGg...TtUuVvWvXxYyZz')) self.sampleEdit.setFixedHeight(self.sampleEdit.sizeHint().height() * 2) self.setFontSelectAvail() def setFontSelectAvail(self): """Disable font selection if default font is checked. Also set the controls with the current or default fonts. """ if self.defaultCheck.isChecked(): font = self.readFont() if font: self.currentFont = font self.setFont(self.printData.defaultFont) self.fontBox.setEnabled(False) else: self.setFont(self.currentFont) self.fontBox.setEnabled(True) def setFont(self, font): """Set the font selector to the given font. Arguments: font -- the QFont to set. """ fontInfo = QFontInfo(font) family = fontInfo.family() matches = self.familyList.findItems(family, Qt.MatchFlag.MatchExactly) if matches: self.familyList.setCurrentItem(matches[0]) self.familyList.scrollToItem(matches[0], QAbstractItemView.ScrollHint. PositionAtTop) style = QFontDatabase.styleString(fontInfo) matches = self.styleList.findItems(style, Qt.MatchFlag.MatchExactly) if matches: self.styleList.setCurrentItem(matches[0]) self.styleList.scrollToItem(matches[0]) else: self.styleList.setCurrentRow(0) self.styleList.scrollToItem(self.styleList.currentItem()) size = repr(fontInfo.pointSize()) matches = self.sizeList.findItems(size, Qt.MatchFlag.MatchExactly) if matches: self.sizeList.setCurrentItem(matches[0]) self.sizeList.scrollToItem(matches[0]) def updateFamily(self, currentItem, previousItem): """Update the family edit box and adjust the style and size options. Arguments: currentItem -- the new list widget family item previousItem -- the previous list widget item """ family = currentItem.text() self.familyEdit.setText(family) if self.familyEdit.hasFocus(): self.familyEdit.selectAll() prevStyle = self.styleEdit.text() prevSize = self.sizeEdit.text() styles = [style for style in QFontDatabase.styles(family)] self.styleList.clear() self.styleList.addItems(styles) if prevStyle: try: num = styles.index(prevStyle) except ValueError: num = 0 self.styleList.setCurrentRow(num) self.styleList.scrollToItem(self.styleList.currentItem()) sizes = [repr(size) for size in QFontDatabase.pointSizes(family)] self.sizeList.clear() self.sizeList.addItems(sizes) if prevSize: try: num = sizes.index(prevSize) except ValueError: num = 0 self.sizeList.setCurrentRow(num) self.sizeList.scrollToItem(self.sizeList.currentItem()) self.updateSample() def updateStyle(self, currentItem, previousItem): """Update the style edit box. Arguments: currentItem -- the new list widget style item previousItem -- the previous list widget item """ if currentItem: style = currentItem.text() self.styleEdit.setText(style) if self.styleEdit.hasFocus(): self.styleEdit.selectAll() self.updateSample() def updateSize(self, currentItem, previousItem): """Update the size edit box. Arguments: currentItem -- the new list widget size item previousItem -- the previous list widget item """ if currentItem: size = currentItem.text() self.sizeEdit.setText(size) if self.sizeEdit.hasFocus(): self.sizeEdit.selectAll() self.updateSample() def updateSample(self): """Update the font sample edit font. """ font = self.readFont() if font: self.sampleEdit.setFont(font) def readFont(self): """Return the selected font or None. """ family = self.familyEdit.text() style = self.styleEdit.text() size = self.sizeEdit.text() if family and style and size: return QFontDatabase.font(family, style, int(size)) return None def saveChanges(self): """Update print data with current dialog settings. Return True if saved settings have changed, False otherwise. """ if self.defaultCheck.isChecked(): if not self.printData.useDefaultFont: self.printData.useDefaultFont = True self.printData.mainFont = self.printData.defaultFont return True else: font = self.readFont() if font and (self.printData.useDefaultFont or font != self.printData.mainFont): self.printData.useDefaultFont = False self.printData.mainFont = font return True return False _headerNames = (_('&Header Left'), _('Header C&enter'), _('Header &Right')) _footerNames = (_('Footer &Left'), _('Footer Ce&nter'), _('Footer Righ&t')) class HeaderPage(QWidget): """Header/footer print option dialog page. """ def __init__(self, printData, parent=None): """Create the header/footer settings page. Arguments: printData -- a reference to the PrintData class parent -- the parent dialog """ super().__init__(parent) self.printData = printData self.focusedEditor = None topLayout = QGridLayout(self) fieldBox = QGroupBox(_('Fiel&ds')) topLayout.addWidget(fieldBox, 0, 0, 3, 1) fieldLayout = QVBoxLayout(fieldBox) self.fieldListWidget = FieldListWidget() fieldLayout.addWidget(self.fieldListWidget) fieldFormatButton = QPushButton(_('Field For&mat')) fieldLayout.addWidget(fieldFormatButton) fieldFormatButton.clicked.connect(self.showFieldFormatDialog) self.addFieldButton = QPushButton('>>') topLayout.addWidget(self.addFieldButton, 0, 1) self.addFieldButton.setMaximumWidth(self.addFieldButton.sizeHint(). height()) self.addFieldButton.clicked.connect(self.addField) self.delFieldButton = QPushButton('<<') topLayout.addWidget(self.delFieldButton, 1, 1) self.delFieldButton.setMaximumWidth(self.delFieldButton.sizeHint(). height()) self.delFieldButton.clicked.connect(self.delField) headerFooterBox = QGroupBox(_('Header and Footer')) topLayout.addWidget(headerFooterBox, 0, 2, 2, 1) headerFooterLayout = QGridLayout(headerFooterBox) spacing = headerFooterLayout.spacing() headerFooterLayout.setVerticalSpacing(0) headerFooterLayout.setRowMinimumHeight(2, spacing) self.headerEdits = self.addLineEdits(_headerNames, headerFooterLayout, 0) self.footerEdits = self.addLineEdits(_footerNames, headerFooterLayout, 3) self.loadContent() def addLineEdits(self, names, layout, startRow): """Add line edits for header or footer. Return a list of line edits added to the top layout. Arguments: names -- a list of label names layout -- the grid layout t use startRow -- the initial row number """ lineEdits = [] for num, name in enumerate(names): label = QLabel(name) layout.addWidget(label, startRow, num) lineEdit = configdialog.TitleEdit() layout.addWidget(lineEdit, startRow + 1, num) label.setBuddy(lineEdit) lineEdit.cursorPositionChanged.connect(self.setControlAvailability) lineEdit.focusIn.connect(self.setCurrentEditor) lineEdits.append(lineEdit) return lineEdits def loadContent(self): """Load field names and header/footer text into the controls. """ self.fieldListWidget.addItems(self.printData.localControl.structure. treeFormats.fileInfoFormat.fieldNames()) self.fieldListWidget.setCurrentRow(0) for text, lineEdit in zip(splitHeaderFooter(self.printData.headerText), self.headerEdits): lineEdit.blockSignals(True) lineEdit.setText(text) lineEdit.blockSignals(False) for text, lineEdit in zip(splitHeaderFooter(self.printData.footerText), self.footerEdits): lineEdit.blockSignals(True) lineEdit.setText(text) lineEdit.blockSignals(False) self.focusedEditor = self.headerEdits[0] self.headerEdits[0].setFocus() self.setControlAvailability() def setControlAvailability(self): """Set controls available based on text cursor movements. """ cursorInField = self.isCursorInField() self.addFieldButton.setEnabled(cursorInField == None) self.delFieldButton.setEnabled(cursorInField == True) def setCurrentEditor(self, sender): """Set focusedEditor based on editor focus change signal. Arguments: sender -- the line editor to focus """ self.focusedEditor = sender self.setControlAvailability() def isCursorInField(self, selectField=False): """Return True if a field pattern encloses the cursor/selection. Return False if the selection overlaps a field. Return None if there is no field at the cursor. Arguments: selectField -- select the entire field pattern if True. """ cursorPos = self.focusedEditor.cursorPosition() selectStart = self.focusedEditor.selectionStart() if selectStart < 0: selectStart = cursorPos elif selectStart == cursorPos: # backward selection cursorPos += len(self.focusedEditor.selectedText()) textLine = self.focusedEditor.text() for match in configdialog.fieldPattern.finditer(textLine): start = (match.start() if match.start() < selectStart < match.end() else None) end = (match.end() if match.start() < cursorPos < match.end() else None) if start != None and end != None: if selectField: self.focusedEditor.setSelection(start, end - start) return True if start != None or end != None: return False return None def addField(self): """Add selected field to cursor pos in current line editor. """ fieldName = self.fieldListWidget.currentItem().text() self.focusedEditor.insert('{{*!{0}*}}'.format(fieldName)) self.focusedEditor.setFocus() def delField(self): """Remove field from cursor pos in current line editor. """ if self.isCursorInField(True): self.focusedEditor.insert('') self.focusedEditor.setFocus() def showFieldFormatDialog(self): """Show thw dialog used to set file info field formats. """ fileInfoFormat = (self.printData.localControl.structure.treeFormats. fileInfoFormat) fieldName = self.fieldListWidget.currentItem().text() field = fileInfoFormat.fieldDict[fieldName] dialog = HeaderFieldFormatDialog(field, self.printData.localControl, self) dialog.exec() def saveChanges(self): """Update print data with current dialog settings. Return True if saved settings have changed, False otherwise. """ changed = False headerList = [lineEdit.text().replace('/', r'\/') for lineEdit in self.headerEdits] while len(headerList) > 1 and not headerList[-1]: del headerList[-1] text = '/'.join(headerList) if self.printData.headerText != text: self.printData.headerText = text changed = True footerList = [lineEdit.text().replace('/', r'\/') for lineEdit in self.footerEdits] while len(footerList) > 1 and not footerList[-1]: del footerList[-1] text = '/'.join(footerList) if self.printData.footerText != text: self.printData.footerText = text changed = True return changed class FieldListWidget(QListWidget): """List widget for fields with smaller width size hint. """ def __init__(self, parent=None): """Create the list widget. Arguments: parent -- the parent dialog """ super().__init__(parent) def sizeHint(self): """Return a size with a smaller width. """ return QSize(120, 100) class HeaderFieldFormatDialog(QDialog): """Dialog to modify file info field formats used in headers and footers. """ def __init__(self, field, localControl, parent=None): """Create the field format dialog. Arguments: field -- the field to be modified localControl -- a ref to the control to save changes and undo """ super().__init__(parent) self.field = field self.localControl = localControl self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Field Format for "{0}"').format(field.name)) topLayout = QVBoxLayout(self) self.setLayout(topLayout) self.formatBox = QGroupBox(_('Output &Format')) topLayout.addWidget(self.formatBox) formatLayout = QHBoxLayout(self.formatBox) self.formatEdit = QLineEdit() formatLayout.addWidget(self.formatEdit) self.helpButton = QPushButton(_('Format &Help')) formatLayout.addWidget(self.helpButton) self.helpButton.clicked.connect(self.formatHelp) extraBox = QGroupBox(_('Extra Text')) topLayout.addWidget(extraBox) extraLayout = QVBoxLayout(extraBox) spacing = extraLayout.spacing() extraLayout.setSpacing(0) prefixLabel = QLabel(_('&Prefix')) extraLayout.addWidget(prefixLabel) self.prefixEdit = QLineEdit() extraLayout.addWidget(self.prefixEdit) prefixLabel.setBuddy(self.prefixEdit) extraLayout.addSpacing(spacing) suffixLabel = QLabel(_('&Suffix')) extraLayout.addWidget(suffixLabel) self.suffixEdit = QLineEdit() extraLayout.addWidget(self.suffixEdit) suffixLabel.setBuddy(self.suffixEdit) ctrlLayout = QHBoxLayout() topLayout.addLayout(ctrlLayout) ctrlLayout.addStretch() okButton = QPushButton(_('&OK')) ctrlLayout.addWidget(okButton) okButton.clicked.connect(self.accept) cancelButton = QPushButton(_('&Cancel')) ctrlLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.prefixEdit.setText(self.field.prefix) self.suffixEdit.setText(self.field.suffix) self.formatEdit.setText(self.field.format) self.formatBox.setEnabled(self.field.defaultFormat != '') def formatHelp(self): """Provide a format help menu based on a button signal. """ menu = QMenu(self) self.formatHelpDict = {} for descript, key in self.field.getFormatHelpMenuList(): if descript: self.formatHelpDict[descript] = key menu.addAction(descript) else: menu.addSeparator() menu.popup(self.helpButton. mapToGlobal(QPoint(0, self.helpButton.height()))) menu.triggered.connect(self.insertFormat) def insertFormat(self, action): """Insert format text from help menu into edit box. Arguments: action -- the action from the help menu """ self.formatEdit.insert(self.formatHelpDict[action.text()]) def accept(self): """Set changes after OK is hit""" prefix = self.prefixEdit.text() suffix = self.suffixEdit.text() format = self.formatEdit.text() if (self.field.prefix != prefix or self.field.suffix != suffix or self.field.format != format): undo.FormatUndo(self.localControl.structure.undoList, self.localControl.structure.treeFormats, treeformats.TreeFormats()) self.field.prefix = prefix self.field.suffix = suffix self.field.format = format self.localControl.setModified() super().accept() _headerSplitRe = re.compile(r'(? _maxActionPathLength: truncLength = _maxActionPathLength - 3 pos = abbrevPath.find(os.sep, len(abbrevPath) - truncLength) if pos < 0: pos = len(abbrevPath) - truncLength abbrevPath = '...' + abbrevPath[pos:] text = '&{0:d} {1}'.format(posNum, abbrevPath) action = QAction(text, globalref.mainControl, statusTip=str(self.pathObj)) action.triggered.connect(self.openFile) return action def openFile(self): """Open this path using the main control method. """ globalref.mainControl.openFile(self.pathObj, checkModified=True) def recordTreeState(self, localControl): """Save the tree state of this item. Arguments: localControl -- the control to store """ self.stateTime = int(time.time()) treeView = localControl.activeWindow.treeView topSpot = treeView.spotAtTop() self.scrollPos = topSpot.spotId() if topSpot else '' self.selectSpots = [spot.spotId() for spot in treeView.selectionModel().selectedSpots()] self.openSpots = [spot.spotId() for spot in localControl.structure. structSpot().expandedSpotDescendantGen(treeView)] self.openSpots = self.openSpots[:_maxOpenNodesStored] def restoreTreeState(self, localControl): """Restore the tree state of this item. Return True if the state was restored. Arguments: localControl -- the control to set state """ fileModTime = self.pathObj.stat().st_mtime if self.stateTime == 0 or fileModTime > self.stateTime: return False # file modified externally treeView = localControl.activeWindow.treeView try: for spotId in self.openSpots: treeView.expandSpot(localControl.structure.spotById(spotId)) if self.scrollPos: treeView.scrollToSpot(localControl.structure. spotById(self.scrollPos)) if self.selectSpots: treeView.selectionModel().selectSpots([localControl.structure. spotById(spotId) for spotId in self.selectSpots]) return True except (KeyError, IndexError): # for old TreeLine import (spotIds don't match) return False def __eq__(self, other): """Test for equality between RecentFileItems and paths. Arguments: other -- either a RecentFileItem or a path string """ try: otherPath = other.pathObj except AttributeError: otherPath = other # use abspath() - pathlib's resolve() can be buggy with network drives return (os.path.abspath(str(self.pathObj)) == os.path.abspath(str(otherPath))) def __ne__(self, other): """Test for inequality between RecentFileItems and paths. Arguments: other -- either a RecentFileItem or a path string """ try: otherPath = other.pathObj except AttributeError: otherPath = other # use abspath() - pathlib's resolve() can be buggy with network drives return (os.path.abspath(str(self.pathObj)) != os.path.abspath(str(otherPath))) class RecentFileList(list): """A list of recent file items. """ def __init__(self): """Load the initial list from the options file. """ super().__init__() self.updateOptions() for data in globalref.histOptions['RecentFiles']: item = RecentFileItem(dataDict=data) if not self.purge or item.pathIsValid(): self.append(item) def updateOptions(self): """Get number of entries and check exists from general options. """ self.numEntries = globalref.genOptions['RecentFiles'] self.purge = globalref.genOptions['PurgeRecentFiles'] def writeItems(self): """Write the recent items to the options file. """ data = [item.dataDict() for item in self[:self.numEntries]] globalref.histOptions.changeValue('RecentFiles', data) def addItem(self, pathObj): """Add the given path at the start of the list. If the path is in the list, move it to the start, otherwise create a new item. Arguments: pathObj -- the new path object to search and/or create """ item = RecentFileItem(pathObj) try: item = self.pop(self.index(item)) except ValueError: pass self.insert(0, item) def removeItem(self, pathObj): """Remove the given path name if found. Arguments: pathObj -- the path to be removed """ try: self.remove(RecentFileItem(pathObj)) except ValueError: pass def getActions(self): """Return a list of actions for ech recent item. """ return [item.itemAction(i) for i, item in enumerate(self[:self.numEntries], 1)] def firstDir(self): """Return a path object of the first valid directory from recent items. """ for item in self: pathObj = item.pathObj.parent try: if pathObj.is_dir(): return pathObj except OSError: pass return None def firstPath(self): """Return the first full path from the recent items if valid. """ if self and self[0].pathIsValid(): return self[0].pathObj return None def saveTreeState(self, localControl): """Save the tree state of the item matching the localControl. Arguments: localControl -- the control to store """ try: item = self[self.index(localControl.filePathObj)] except (ValueError, TypeError, AttributeError, OSError): return item.recordTreeState(localControl) def retrieveTreeState(self, localControl): """Restore the saved tree state of the item matching the localControl. Return True if the state was restored. Arguments: localControl -- the control to restore state """ try: item = self[self.index(localControl.filePathObj)] except (ValueError, AttributeError): return False return item.restoreTreeState(localControl) TreeLine-3.2.1/source/setup.py000066400000000000000000000035611506556630100162520ustar00rootroot00000000000000#****************************************************************************** # setup.py, provides a distutils script for use with cx_Freeze # # Creates a standalone windows executable # # Run the build process by running the command 'python setup.py build' # # If everything works well you should find a subdirectory in the build # subdirectory that contains the files needed to run the application # # TreeLine, an information storage program # Copyright (C) 2018, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import sys from cx_Freeze import setup, Executable from treeline import __version__ base = None if sys.platform == 'win32': base = 'Win32GUI' extraFiles = [('../doc', 'doc'), ('../icons', 'icons'), ('../samples', 'samples'), ('../source', 'source'), ('../templates', 'templates'), ('../translations', 'translations'), ('../win', '.')] setup(name = 'treeline', version = __version__, description = 'TreeLine info storage program', options = {'build_exe': {'includes': ['atexit', 'PyQt5.sip'], 'include_files': extraFiles, 'excludes': ['*.pyc'], 'zip_include_packages': ['*'], 'zip_exclude_packages': [], 'include_msvcr': True, 'build_exe': '../../TreeLine-3.0'}}, executables = [Executable('treeline.py', base=base, icon='../win/treeline.ico')]) TreeLine-3.2.1/source/spellcheck.py000066400000000000000000000541031506556630100172250ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # spellcheck.py, provides classes for spell check interfaces and dialogs, # including interfaces to aspell, ispell, hunspell. # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import sys import subprocess import collections from PyQt6.QtCore import QSize, Qt, pyqtSignal from PyQt6.QtGui import QFontMetrics, QTextCursor from PyQt6.QtWidgets import (QApplication, QDialog, QFileDialog, QGroupBox, QHBoxLayout, QLabel, QLineEdit, QListWidget, QMessageBox, QPushButton, QTextEdit, QVBoxLayout) import undo import globalref _guessRe = re.compile(r'[&?] (\S+) \d+ (\d+): (.+)') _noGuessRe = re.compile(r'# (\S+) (\d+)') class SpellCheckInterface: """Interfaces with aspell, ispell or hunspell and stores session hooks. """ def __init__(self, spellPath='', langCode=''): """Create initial hooks to outside program. Arguments: spellPath -- use to find engine executable if given langCode -- language code to pass to aspell if given """ engineOptions = collections.OrderedDict() engineOptions.update([('aspell', ['-a -H --encoding=utf-8']), ('ispell', ['-a -h -Tutf8', '-a']), ('hunspell', ['-a -H -i utf-8'])]) langPrefix = {'aspell': 'l', 'ispell': 'd', 'hunspell': 'd'} if spellPath: newEngineOptions = {} for engine in engineOptions.keys(): if engine in spellPath: newEngineOptions[spellPath] = engineOptions[engine] engineOptions = newEngineOptions for engine, options in engineOptions.items(): if langCode: options.insert(0, '{0} -{1} {2}'.format(options[0], langPrefix[engine], langCode)) for option in options: cmd = '{0} {1}'.format(engine, option) try: p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.stdIn = p.stdin self.stdOut = p.stdout self.stdOut.readline() # read header # set terse mode (no correct returns) self.stdIn.write(b'!\n') self.stdIn.flush() return except IOError: pass raise SpellCheckError('Could not initialize aspell, ispell or ' 'hunspell') def checkLine(self, line, skipWords=None): """Check one (and only one) line of text. Return a list of tuples, each with the mispelled word, position in the line, and a list of suggestions. Arguments: line -- the text string to check skipWords -- a set of words to ignore if given """ if not skipWords: skipWords = set() self.stdIn.write('^{0}\n'.format(line).encode('utf-8')) self.stdIn.flush() outputs = [self.stdOut.readline()] while outputs[-1].strip(): outputs.append(self.stdOut.readline()) results = [] for output in outputs: output = output.decode('utf-8').strip() match = _guessRe.match(output) if match: guesses = match.group(3).split(', ') else: match = _noGuessRe.match(output) guesses = [] if match: word = match.group(1) if word not in skipWords: wordPos = int(match.group(2)) - 1 # work around unicode bug in older versions of aspell while (line[wordPos:wordPos + len(word)] != word and wordPos > 0): wordPos -= 1 results.append((word, wordPos, guesses)) return results def close(self): """Shut down hooks to outside program. """ self.stdIn.close() self.stdOut.close() def acceptWord(self, word): """Accept given word for the remainder of this session. Arguments: word -- the word to accept """ self.stdIn.write('@{0}\n'.format(word).encode('utf-8')) self.stdIn.flush() def addToDict(self, word, lowCase=False): """Add word to spell check engine's dictionary. Arguments: word -- the word to add lowCase -- if True, add the word as a lower case word """ if lowCase: self.stdIn.write('&{0}\n'.format(word).encode('utf-8')) else: self.stdIn.write('*{0}\n'.format(word).encode('utf-8')) self.stdIn.write(b'#\n') # saves dict self.stdIn.flush() class SpellCheckError(Exception): """Exception class for errors interfacing with the spell check engine. """ pass # console test for the spell check engine interface if __name__ == '__main__': try: sp = SpellCheckInterface() except SpellCheckError: print('Error - could not initialize aspell, ispell or hunspell') sys.exit() while True: s = input('Enter line-> ').strip() if not s: sys.exit() if s.startswith('Accept->'): sp.acceptWord(s[8:]) elif s.startswith('Add->'): sp.addToDict(s[5:]) elif s.startswith('AddLow->'): sp.addToDict(s[8:], True) else: for word, pos, suggests in sp.checkLine(s): print('{0} @{1}: {2}\n'.format(word, pos, ', '.join(suggests))) sp.close() class SpellCheckOperation: """Feeds tree node text to the spell check dialog. """ def __init__(self, controlRef): """Initialize the spell check engine interface. Arguments: controlRef - the local control """ self.controlRef = controlRef self.selectModel = controlRef.currentSelectionModel() self.currentSpot = None self.currentField = '' self.lineNum = 0 self.textLine = '' parentWidget = QApplication.activeWindow() path = globalref.miscOptions['SpellCheckPath'] while True: try: self.spellCheckInterface = SpellCheckInterface(path, self.controlRef. spellCheckLang) return except SpellCheckError: if path: path = '' else: if sys.platform.startswith('win'): prompt = (_('Could not find either aspell.exe, ' 'ispell.exe or hunspell.exe\n' 'Browse for location?')) ans = QMessageBox.warning(parentWidget, _('Spell Check Error'), prompt, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.Cancel, QMessageBox.StandardButton.Yes) if ans == QMessageBox.StandardButton.Cancel: raise title = _('Locate aspell.exe, ipsell.exe or ' 'hunspell.exe') path, fltr = QFileDialog.getOpenFileName(parentWidget, title, '', _('Program (*.exe)')) if path: path = path[:-4] if ' ' in path: path = '"{0}"'.format(path) globalref.miscOptions.changeValue('SpellCheckPath', path) globalref.miscOptions.writeFile() else: prompt = (_('TreeLine Spell Check Error\nMake sure ' 'aspell, ispell or hunspell is installed')) QMessageBox.warning(parentWidget, 'TreeLine', prompt) raise def spellCheck(self): """Spell check starting with the selected branches. """ parentWidget = QApplication.activeWindow() spellCheckDialog = SpellCheckDialog(self.spellCheckInterface, parentWidget) spellCheckDialog.misspellFound.connect(self.updateSelection) spellCheckDialog.changeRequest.connect(self.changeNode) origBranches = self.selectModel.selectedBranchSpots() if not origBranches: origBranches = self.controlRef.structure.rootSpots() result = (spellCheckDialog. startSpellCheck(self.textLineGenerator(origBranches))) self.selectModel.selectSpots(origBranches, expandParents = True) if result and origBranches[0].parentSpot.parentSpot: prompt = _('Finished checking the branch\nContinue from the top?') ans = QMessageBox.information(parentWidget, _('TreeLine Spell Check'), prompt, QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) if ans == QMessageBox.StandardButton.Yes: generator = self.textLineGenerator(self.controlRef.structure. rootSpots()) result = spellCheckDialog.startSpellCheck(generator) self.selectModel.selectSpots(origBranches, expandParents = True) else: result = False if result: QMessageBox.information(parentWidget, _('TreeLine Spell Check'), _('Finished spell checking')) def updateSelection(self): """Change the tree selection to the node with a misspelled word. """ self.selectModel.selectSpots([self.currentSpot], expandParents = True) def changeNode(self, newTextLine): """Replace the current text line in the current node. Arguments: newTextLine -- the new text to use """ node = self.currentSpot.nodeRef undo.DataUndo(self.controlRef.structure.undoList, node) textLines = node.data.get(self.currentField, '').split('\n') textLines[self.lineNum] = newTextLine node.data[self.currentField] = '\n'.join(textLines) self.controlRef.updateTreeNode(node) def textLineGenerator(self, branches): """Yield next line to be checked. Arguments: branches -- a list of branch parent nodes to check. """ for parent in branches: for self.currentSpot in parent.spotDescendantGen(): node = self.currentSpot.nodeRef for self.currentField in node.formatRef.fieldNames(): text = node.data.get(self.currentField, '') if text: for self.lineNum, self.textLine in \ enumerate(text.split('\n')): yield self.textLine class SpellCheckDialog(QDialog): """Dialog to perform and control the spell check operation. """ misspellFound = pyqtSignal() changeRequest = pyqtSignal(str) def __init__(self, spellCheckInterface, parent=None): """Create the dialog. Arguments: spellCheckInterface -- a reference to the spell engine interface parent -- the parent dialog """ super().__init__(parent) self.setWindowFlags(Qt.WindowType.Dialog | Qt.WindowType.WindowTitleHint | Qt.WindowType.WindowCloseButtonHint) self.setWindowTitle(_('Spell Check')) self.spellCheckInterface = spellCheckInterface self.textLineIter = None self.textLine = '' self.replaceAllDict = {} self.tmpIgnoreWords = set() self.word = '' self.postion = 0 topLayout = QHBoxLayout(self) leftLayout = QVBoxLayout() topLayout.addLayout(leftLayout) wordBox = QGroupBox(_('Not in Dictionary')) leftLayout.addWidget(wordBox) wordLayout = QVBoxLayout(wordBox) label = QLabel(_('Word:')) wordLayout.addWidget(label) self.wordEdit = QLineEdit() wordLayout.addWidget(self.wordEdit) self.wordEdit.textChanged.connect(self.updateFromWord) wordLayout.addSpacing(5) label = QLabel(_('Context:')) wordLayout.addWidget(label) self.contextEdit = SpellContextEdit() wordLayout.addWidget(self.contextEdit) self.contextEdit.textChanged.connect(self.updateFromContext) suggestBox = QGroupBox(_('Suggestions')) leftLayout.addWidget(suggestBox) suggestLayout = QVBoxLayout(suggestBox) self.suggestList = QListWidget() suggestLayout.addWidget(self.suggestList) self.suggestList.itemDoubleClicked.connect(self.replace) rightLayout = QVBoxLayout() topLayout.addLayout(rightLayout) ignoreButton = QPushButton(_('Ignor&e')) rightLayout.addWidget(ignoreButton) ignoreButton.clicked.connect(self.ignore) ignoreAllButton = QPushButton(_('&Ignore All')) rightLayout.addWidget(ignoreAllButton) ignoreAllButton.clicked.connect(self.ignoreAll) rightLayout.addStretch() addButton = QPushButton(_('&Add')) rightLayout.addWidget(addButton) addButton.clicked.connect(self.add) addLowerButton = QPushButton(_('Add &Lowercase')) rightLayout.addWidget(addLowerButton) addLowerButton.clicked.connect(self.addLower) rightLayout.addStretch() replaceButton = QPushButton(_('&Replace')) rightLayout.addWidget(replaceButton) replaceButton.clicked.connect(self.replace) self.replaceAllButton = QPushButton(_('Re&place All')) rightLayout.addWidget(self.replaceAllButton) self.replaceAllButton.clicked.connect(self.replaceAll) rightLayout.addStretch() cancelButton = QPushButton(_('&Cancel')) rightLayout.addWidget(cancelButton) cancelButton.clicked.connect(self.reject) self.widgetDisableList = [ignoreButton, ignoreAllButton, addButton, addLowerButton, self.suggestList] self.fullDisableList = (self.widgetDisableList + [self.replaceAllButton, self.wordEdit]) def startSpellCheck(self, textLineIter): """Spell check text lines given in the iterator. Block execution except for the dialog if mispellings are found. Return True if spell check completes, False if cancelled. Arguments: textLineIter -- an iterator of text lines to check """ self.textLineIter = textLineIter try: self.textLine = next(self.textLineIter) except StopIteration: return True if self.spellCheck(): if self.exec() == QDialog.DialogCode.Rejected: return False return True def continueSpellCheck(self): """Check lines, starting with current line. Exit the dialog if there are no more lines to check. """ if not self.spellCheck(): self.accept() def spellCheck(self): """Step through the iterator and spell check the lines. If results found, update the dialog with the results and return True. Return false if the end of the iterator is reached. """ while True: results = self.spellCheckInterface.checkLine(self.textLine, self.tmpIgnoreWords) if results: self.word, self.position, suggestions = results[0] newWord = self.replaceAllDict.get(self.word, '') if newWord: self.textLine = self.replaceWord(newWord) self.changeRequest.emit(self.textLine) else: self.misspellFound.emit() self.setWord(suggestions) return True try: self.textLine = next(self.textLineIter) self.tmpIgnoreWords.clear() except StopIteration: return False def setWord(self, suggestions): """Set dialog contents from the checked line and spell check results. Arguments: suggestions -- a list of suggested replacement words """ self.wordEdit.blockSignals(True) self.wordEdit.setText(self.word) self.wordEdit.blockSignals(False) self.contextEdit.blockSignals(True) self.contextEdit.setPlainText(self.textLine) self.contextEdit.setSelection(self.position, self.position + len(self.word)) self.contextEdit.blockSignals(False) self.suggestList.clear() self.suggestList.addItems(suggestions) self.suggestList.setCurrentItem(self.suggestList.item(0)) for widget in self.fullDisableList: widget.setEnabled(True) def replaceWord(self, newWord): """Return textLine with word replaced with newWord. Arguments: newWord -- the replacement word """ return (self.textLine[:self.position] + newWord + self.textLine[self.position + len(self.word):]) def ignore(self): """Set word to ignored (this check only) and continue spell check. """ self.tmpIgnoreWords.add(self.word) self.continueSpellCheck() def ignoreAll(self): """Add to dictionary's ignore list and continue spell check. """ self.spellCheckInterface.acceptWord(self.word) self.continueSpellCheck() def add(self): """Add misspelling to dictionary and continue spell check""" self.spellCheckInterface.addToDict(self.word, False) self.continueSpellCheck() def addLower(self): """Add misspelling to dictionary as lowercase and continue spell check. """ self.spellCheckInterface.addToDict(self.word, True) self.continueSpellCheck() def replace(self): """Replace misspelled word with suggestion or context edit box Then continue spell check. """ if self.suggestList.isEnabled(): newWord = self.suggestList.currentItem().text() self.textLine = self.replaceWord(newWord) else: self.textLine = self.contextEdit.toPlainText() self.changeRequest.emit(self.textLine) self.continueSpellCheck() def replaceAll(self): """Replace misspelled word with suggestion or word edit (in future too). Stores changed word in replaceAllDict and continues spell check. """ if self.suggestList.isEnabled(): newWord = self.suggestList.currentItem().text() else: newWord = self.wordEdit.text() self.textLine = self.replaceWord(newWord) self.replaceAllDict[self.word] = newWord self.changeRequest.emit(self.textLine) self.continueSpellCheck() def updateFromWord(self): """Update dialog after word line editor change. Disables suggests and ignore/add controls. Updates the context editor. """ for widget in self.widgetDisableList: widget.setEnabled(False) newWord = self.wordEdit.text() self.suggestList.clearSelection() self.contextEdit.blockSignals(True) self.contextEdit.setPlainText(self.replaceWord(newWord)) self.contextEdit.setSelection(self.position, self.position + len(newWord)) self.contextEdit.blockSignals(False) def updateFromContext(self): """Update dialog after context editor change. Disables controls except for replace. """ for widget in self.fullDisableList: widget.setEnabled(False) self.suggestList.clearSelection() class SpellContextEdit(QTextEdit): """Editor for spell check word context. Sets the size hint to 3 lines and simplifies selction. """ def __init__(self, parent=None): """Create the editor. Arguments: parent -- the parent widget """ super().__init__(parent) self.setTabChangesFocus(True) def sizeHint(self): """Set prefered size of 3 lines long. """ fontHeight = QFontMetrics(self.currentFont()).lineSpacing() return QSize(QTextEdit.sizeHint(self).width(), fontHeight * 3) def setSelection(self, fromPos, toPos): """Select the given range in first paragraph. Arguments: fromPos -- the starting position toPos -- the ending position """ cursor = self.textCursor() cursor.setPosition(fromPos) cursor.setPosition(toPos, QTextCursor.MoveMode.KeepAnchor) self.setTextCursor(cursor) self.ensureCursorVisible() TreeLine-3.2.1/source/titlelistview.py000066400000000000000000000234451506556630100200250ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # titlelistview.py, provides a class for the title list view # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtGui import QAction, QKeySequence, QPalette, QTextCursor from PyQt6.QtWidgets import QTextEdit import treenode import undo import globalref class TitleListView(QTextEdit): """Class override for the title list view. Sets view defaults and updates the content. """ nodeModified = pyqtSignal(treenode.TreeNode) treeModified = pyqtSignal() shortcutEntered = pyqtSignal(QKeySequence) def __init__(self, treeView, isChildView=True, parent=None): """Initialize the title list view. Arguments: treeView - the tree view, needed for the current selection model isChildView -- shows selected nodes if false, child nodes if true parent -- the parent main window """ super().__init__(parent) self.treeView = treeView self.isChildView = isChildView self.hideChildView = not globalref.genOptions['InitShowChildPane'] self.setAcceptRichText(False) self.setLineWrapMode(QTextEdit.LineWrapMode.NoWrap) self.setTabChangesFocus(True) self.setUndoRedoEnabled(False) self.treeSelectAction = QAction(_('Select in Tree'), self) self.treeSelectAction.triggered.connect(self.selectLineInTree) self.textChanged.connect(self.readChange) def updateContents(self): """Reload the view's content if the view is shown. Avoids update if view is not visible or has zero height or width. """ selSpots = self.treeView.selectionModel().selectedSpots() if self.isChildView: if len(selSpots) > 1 or self.hideChildView: self.hide() return if not selSpots: # use top node childList from tree structure selSpots = [globalref.mainControl.activeControl.structure. structSpot()] elif not selSpots: self.hide() return self.show() if not self.isVisible() or self.height() == 0 or self.width() == 0: return if self.isChildView: selSpots = selSpots[0].childSpots() self.blockSignals(True) if selSpots: self.setPlainText('\n'.join(spot.nodeRef.title(spot) for spot in selSpots)) else: self.clear() self.blockSignals(False) def readChange(self): """Update nodes after edited by user. """ textList = [' '.join(text.split()) for text in self.toPlainText(). split('\n') if text.strip()] selSpots = self.treeView.selectionModel().selectedSpots() treeStructure = globalref.mainControl.activeControl.structure if self.isChildView: if not selSpots: selSpots = [treeStructure.structSpot()] parentSpot = selSpots[0] parent = parentSpot.nodeRef selSpots = parentSpot.childSpots() if len(selSpots) == len(textList): # collect changes first to skip false clone changes changes = [(spot.nodeRef, text) for spot, text in zip(selSpots, textList) if spot.nodeRef.title(spot) != text] for node, text in changes: undoObj = undo.DataUndo(treeStructure.undoList, node, skipSame=True) if node.setTitle(text): self.nodeModified.emit(node) else: treeStructure.undoList.removeLastUndo(undoObj) elif self.isChildView and (textList or parent != treeStructure): undo.ChildDataUndo(treeStructure.undoList, parent) # clear hover to avoid crash if deleted child item was hovered over self.treeView.clearHover() isDeleting = len(selSpots) > len(textList) control = globalref.mainControl.activeControl if isDeleting and len(control.windowList) > 1: # clear other window selections that are about to be deleted for window in control.windowList: if window != control.activeWindow: selectModel = window.treeView.selectionModel() ancestors = set() for spot in selectModel.selectedBranchSpots(): ancestors.update(set(spot.spotChain())) if ancestors & set(selSpots): selectModel.selectSpots([], False) expandState = self.treeView.savedExpandState(selSpots) parent.replaceChildren(textList, treeStructure) self.treeView.restoreExpandState(expandState) if self.treeView.selectionModel().selectedSpots(): self.treeView.expandSpot(parentSpot) self.treeModified.emit() else: self.updateContents() # remove illegal changes def selectLineInTree(self): """Select the node for the current line in the tree view. """ selSpots = self.treeView.selectionModel().selectedSpots() if not selSpots: selSpots = [treeStructure.structSpot()] spotList = selSpots[0].childSpots() cursor = self.textCursor() blockStart = cursor.block().position() # check for selection all on one line if (cursor.selectionStart() >= blockStart and cursor.selectionEnd() < blockStart + cursor.block().length()): lineNum = cursor.blockNumber() if len(spotList) > lineNum: self.treeView.selectionModel().selectSpots([spotList[lineNum]], True, True) def hasSelectedText(self): """Return True if text is selected. """ return self.textCursor().hasSelection() def highlightSearch(self, wordList=None, regExpList=None): """Highlight any found search terms. Arguments: wordList -- list of words to highlight regExpList -- a list of regular expression objects to highlight """ backColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.Highlight) foreColor = self.palette().brush(QPalette.ColorGroup.Active, QPalette.ColorRole.HighlightedText) if wordList is None: wordList = [] if regExpList is None: regExpList = [] for regExp in regExpList: for match in regExp.finditer(self.toPlainText()): matchText = match.group() if matchText not in wordList: wordList.append(matchText) selections = [] for word in wordList: while self.find(word): extraSel = QTextEdit.ExtraSelection() extraSel.cursor = self.textCursor() extraSel.format.setBackground(backColor) extraSel.format.setForeground(foreColor) selections.append(extraSel) cursor = QTextCursor(self.document()) self.setTextCursor(cursor) # reset main cursor/selection self.setExtraSelections(selections) def focusInEvent(self, event): """Handle focus-in to put cursor at end for tab-based focus. Arguments: event -- the focus in event """ if event.reason() in (Qt.FocusReason.TabFocusReason, Qt.FocusReason.BacktabFocusReason): self.moveCursor(QTextCursor.MoveOperation.End) super().focusInEvent(event) def contextMenuEvent(self, event): """Override popup menu to remove local undo. Arguments: event -- the menu event """ menu = self.createStandardContextMenu() menu.removeAction(menu.actions()[0]) menu.removeAction(menu.actions()[0]) menu.insertSeparator(menu.actions()[0]) menu.insertAction(menu.actions()[0], self.treeSelectAction) self.treeSelectAction.setEnabled(self.isChildView and len(self.toPlainText().strip()) > 0) menu.exec(event.globalPos()) def keyPressEvent(self, event): """Customize handling of return and control keys. Ignore return key if not in show children mode and emit a signal for app to handle control keys. Arguments: event -- the key press event """ if (event.modifiers() == Qt.KeyboardModifier.ControlModifier and Qt.Key.Key_A <= event.key() <= Qt.Key.Key_Z): key = QKeySequence(event.keyCombination()) self.shortcutEntered.emit(key) return if self.isChildView or event.key() not in (Qt.Key.Key_Enter, Qt.Key.Key_Return): super().keyPressEvent(event) def resizeEvent(self, event): """Update view if it was collaped by splitter. """ if ((event.oldSize().height() == 0 and event.size().height()) or (event.oldSize().width() == 0 and event.size().width())): self.updateContents() return super().resizeEvent(event) TreeLine-3.2.1/source/treeformats.py000066400000000000000000000454271506556630100174540ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treeformats.py, provides a class to store node format types and info # # TreeLine, an information storage program # Copyright (C) 2023, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import operator import copy import xml.sax.saxutils import nodeformat import matheval import conditional import treenode import treestructure defaultTypeName = _('DEFAULT') _showConfRootTypeName = _('FILE') _showConfTypeTypeName = _('TYPE') _showConfTypeTitleFieldName = _('TitleFormat') _showConfTypeOutputFieldName = _('OutputFormat') _showConfTypeSpaceFieldName = _('SpaceBetween') _showConfTypeHtmlFieldName = _('FormatHtml') _showConfTypeBulletsFieldName = _('Bullets') _showConfTypeTableFieldName = _('Table') _showConfTypeChildFieldName = _('ChildType') _showConfTypeIconFieldName = _('Icon') _showConfTypeGenericFieldName = _('GenericType') _showConfTypeConditionFieldName = _('ConditionalRule') _showConfTypeSeparatorFieldName = _('ListSeparator') _showConfTypeChildLimitFieldName = _('ChildTypeLimit') _showConfFieldTypeName = _('FIELD') _showConfFieldTypeFieldName = _('FieldType') _showConfFieldFormatFieldName = _('Format') _showConfFieldPrefixFieldName = _('Prefix') _showConfFieldSuffixFieldName = _('Suffix') _showConfFieldInitFieldName = _('InitialValue') _showConfFieldLinesFieldName = _('NumLines') _showConfFieldSortKeyFieldName = _('SortKeyNum') _showConfFieldSortDirFieldName = _('SortForward') _showConfFieldEvalHtmlFieldName = _('EvalHtml') class TreeFormats(dict): """Class to store node format types and info. Stores node formats by format name in a dictionary. Provides methods to change and update format data. """ def __init__(self, formatList=None, setDefault=False): """Initialize the format storage. Arguments: formatList -- the list of formats' file info setDefault - if true, initializes with a default format """ super().__init__() # new names for types renamed in the config dialog (orig names as keys) self.typeRenameDict = {} # nested dict for fields renamed, keys are type name then orig field self.fieldRenameDict = {} self.conditionalTypes = set() # set of math field names with deleted equations, keys are type names self.emptiedMathDict = {} self.mathFieldRefDict = {} # list of math eval levels, each is a dict by type name with lists of # equation fields self.mathLevelList = [] # for saving all-type find/filter conditionals self.savedConditionText = {} # used by copied configs in config dialog self.configModified = False self.fileInfoFormat = nodeformat.FileInfoFormat(self) if formatList: for formatData in formatList: name = formatData['formatname'] self[name] = nodeformat.NodeFormat(name, self, formatData) self.updateDerivedRefs() try: self.updateMathFieldRefs() except matheval.CircularMathError: # can see if types with math fields were copied from a 2nd file # handle the exception to avoid failure at file open print('Warning - Circular math fields detected') if nodeformat.FileInfoFormat.typeName in self: self.fileInfoFormat.duplicateFileInfo(self[nodeformat. FileInfoFormat. typeName]) del self[nodeformat.FileInfoFormat.typeName] if setDefault: self[defaultTypeName] = nodeformat.NodeFormat(defaultTypeName, self, addDefaultField=True) def storeFormats(self): """Return a list of formats stored in JSON data. """ formats = list(self.values()) if self.fileInfoFormat.fieldFormatModified: formats.append(self.fileInfoFormat) return sorted([nodeFormat.storeFormat() for nodeFormat in formats], key=operator.itemgetter('formatname')) def loadGlobalSavedConditions(self, propertyDict): """Load all-type saved conditionals from property dict. Arguments: propertyDict -- a JSON property dict """ for key in propertyDict.keys(): if key.startswith('glob-cond-'): self.savedConditionText[key[10:]] = propertyDict[key] def storeGlobalSavedConditions(self, propertyDict): """Save all-type saved conditionals to property dict. Arguments: propertyDict -- a JSON property dict """ for key, text in self.savedConditionText.items(): propertyDict['glob-cond-' + key] = text return propertyDict def copySettings(self, sourceFormats): """Copy all settings from other type formats to these formats. Copy any new formats and delete any missing formats. Arguments: sourceFormats -- the type formats to copy """ if sourceFormats.typeRenameDict: for oldName, newName in sourceFormats.typeRenameDict.items(): try: self[oldName].name = newName except KeyError: pass # skip if new type is renamed formats = list(self.values()) self.clear() for nodeFormat in formats: self[nodeFormat.name] = nodeFormat sourceFormats.typeRenameDict = {} for name in list(self.keys()): if name in sourceFormats: self[name].copySettings(sourceFormats[name]) else: del self[name] for name in sourceFormats.keys(): if name not in self: self[name] = copy.deepcopy(sourceFormats[name]) if (sourceFormats.fileInfoFormat.fieldFormatModified or self.fileInfoFormat.fieldFormatModified): self.fileInfoFormat.duplicateFileInfo(sourceFormats.fileInfoFormat) def typeNames(self): """Return a sorted list of type names. """ return sorted(list(self.keys())) def updateLineParsing(self): """Update the fields parsed in the output lines for each format type. """ for typeFormat in self.values(): typeFormat.updateLineParsing() def addTypeIfMissing(self, typeFormat): """Add format to available types if not a duplicate. Arguments: typeFormat -- the node format to add """ self.setdefault(typeFormat.name, typeFormat) def fieldNameDict(self): """Return a dictionary of field name sets using type names as keys. """ result = {} for typeFormat in self.values(): result[typeFormat.name] = set(typeFormat.fieldNames()) return result def updateDerivedRefs(self): """Update derived type lists (in generics) & the conditional type set. """ self.conditionalTypes = set() for typeFormat in self.values(): typeFormat.derivedTypes = [] if typeFormat.conditional: self.conditionalTypes.add(typeFormat) if typeFormat.genericType: self.conditionalTypes.add(self[typeFormat.genericType]) for typeFormat in self.values(): if typeFormat.genericType: genericType = self[typeFormat.genericType] genericType.derivedTypes.append(typeFormat) if genericType in self.conditionalTypes: self.conditionalTypes.add(typeFormat) for typeFormat in self.values(): if not typeFormat.genericType and not typeFormat.derivedTypes: typeFormat.conditional = None self.conditionalTypes.discard(typeFormat) def updateMathFieldRefs(self): """Update refs used to cycle thru math field evaluations. """ self.mathFieldRefDict = {} allRecursiveRefs = [] recursiveRefDict = {} matheval.RecursiveEqnRef.recursiveRefDict = recursiveRefDict for typeFormat in self.values(): for field in typeFormat.fields(): if field.typeName == 'Math' and field.equation: recursiveRef = matheval.RecursiveEqnRef(typeFormat.name, field) allRecursiveRefs.append(recursiveRef) recursiveRefDict.setdefault(field.name, []).append(recursiveRef) for fieldRef in field.equation.fieldRefs: fieldRef.eqnNodeTypeName = typeFormat.name fieldRef.eqnFieldName = field.name self.mathFieldRefDict.setdefault(fieldRef.fieldName, []).append(fieldRef) if not allRecursiveRefs: return for ref in allRecursiveRefs: ref.setPriorities() allRecursiveRefs.sort() self.mathLevelList = [{allRecursiveRefs[0].eqnTypeName: [allRecursiveRefs[0]]}] for prevRef, currRef in zip(allRecursiveRefs, allRecursiveRefs[1:]): if currRef.evalSequence == prevRef.evalSequence: if prevRef.evalDirection == matheval.EvalDir.optional: prevRef.evalDirection = currRef.evalDirection elif currRef.evalDirection == matheval.EvalDir.optional: currRef.evalDirection = prevRef.evalDirection if currRef.evalDirection != prevRef.evalDirection: self.mathLevelList.append({}) else: self.mathLevelList.append({}) self.mathLevelList[-1].setdefault(currRef.eqnTypeName, []).append(currRef) def numberingFieldDict(self): """Return a dict of numbering field names by node format name. """ result = {} for typeFormat in self.values(): numberingFields = typeFormat.numberingFieldList() if numberingFields: result[typeFormat.name] = numberingFields return result def commonFields(self, nodes): """Return a list of field names common to all given node formats. Retains the field sequence from one of the types. Arguments: nodes -- the nodes to check for common fields """ formats = set() for node in nodes: formats.add(node.formatRef.name) firstFields = self[formats.pop()].fieldNames() commonFields = set(firstFields) for formatName in formats: commonFields.intersection_update(self[formatName].fieldNames()) return [field for field in firstFields if field in commonFields] def savedConditions(self): """Return a dictionary with saved Conditonals from all type formats. """ savedConditions = {} # all-type conditions for name, text in self.savedConditionText.items(): cond = conditional.Conditional(text) savedConditions[name] = cond # specific type conditions for typeFormat in self.values(): for name, text in typeFormat.savedConditionText.items(): cond = conditional.Conditional(text, typeFormat.name) savedConditions[name] = cond return savedConditions def visualConfigStructure(self, fileName): """Export a TreeLine structure containing the config types and fields. Returns the structure. Arguments: fileName -- the name for the root node """ structure = treestructure.TreeStructure() structure.treeFormats = TreeFormats() rootFormat = nodeformat.NodeFormat(_showConfRootTypeName, structure.treeFormats, addDefaultField=True) structure.treeFormats[rootFormat.name] = rootFormat typeFormat = nodeformat.NodeFormat(_showConfTypeTypeName, structure.treeFormats, addDefaultField=True) typeFormat.addField(_showConfTypeTitleFieldName) typeFormat.addField(_showConfTypeOutputFieldName) typeFormat.addField(_showConfTypeSpaceFieldName, {'fieldtype': 'Boolean'}) typeFormat.addField(_showConfTypeHtmlFieldName, {'fieldtype': 'Boolean'}) typeFormat.addField(_showConfTypeBulletsFieldName, {'fieldtype': 'Boolean'}) typeFormat.addField(_showConfTypeTableFieldName, {'fieldtype': 'Boolean'}) typeFormat.addField(_showConfTypeChildFieldName) typeFormat.addField(_showConfTypeIconFieldName) typeFormat.addField(_showConfTypeGenericFieldName) typeFormat.addField(_showConfTypeConditionFieldName) typeFormat.addField(_showConfTypeSeparatorFieldName) typeFormat.addField(_showConfTypeChildLimitFieldName) structure.treeFormats[typeFormat.name] = typeFormat fieldFormat = nodeformat.NodeFormat(_showConfFieldTypeName, structure.treeFormats, addDefaultField=True) fieldFormat.addField(_showConfFieldTypeFieldName) fieldFormat.addField(_showConfFieldFormatFieldName) fieldFormat.addField(_showConfFieldPrefixFieldName) fieldFormat.addField(_showConfFieldSuffixFieldName) fieldFormat.addField(_showConfFieldInitFieldName) fieldFormat.addField(_showConfFieldLinesFieldName, {'fieldtype': 'Number'}) fieldFormat.addField(_showConfFieldSortKeyFieldName, {'fieldtype': 'Number'}) fieldFormat.addField(_showConfFieldSortDirFieldName, {'fieldtype': 'Boolean'}) fieldFormat.addField(_showConfFieldEvalHtmlFieldName, {'fieldtype': 'Boolean'}) line = '{{*{0}*}} ({{*{1}*}})'.format(nodeformat.defaultFieldName, _showConfFieldTypeFieldName) fieldFormat.changeTitleLine(line) fieldFormat.changeOutputLines([line]) structure.treeFormats[fieldFormat.name] = fieldFormat rootNode = treenode.TreeNode(rootFormat) structure.childList.append(rootNode) structure.addNodeDictRef(rootNode) rootNode.data[nodeformat.defaultFieldName] = fileName for typeName in self.typeNames(): typeNode = treenode.TreeNode(typeFormat) rootNode.childList.append(typeNode) structure.addNodeDictRef(typeNode) typeNode.data[nodeformat.defaultFieldName] = typeName titleLine = self[typeName].getTitleLine() outputList = self[typeName].getOutputLines() if self[typeName].formatHtml: titleLine = xml.sax.saxutils.escape(titleLine) outputList = [xml.sax.saxutils.escape(line) for line in outputList] outputLines = '
    \n'.join(outputList) typeNode.data[_showConfTypeTitleFieldName] = titleLine typeNode.data[_showConfTypeOutputFieldName] = outputLines spaceBetween = repr(self[typeName].spaceBetween) typeNode.data[_showConfTypeSpaceFieldName] = spaceBetween formatHtml = repr(self[typeName].formatHtml) typeNode.data[_showConfTypeHtmlFieldName] = formatHtml useBullets = repr(self[typeName].useBullets) typeNode.data[_showConfTypeBulletsFieldName] = useBullets useTables = repr(self[typeName].useTables) typeNode.data[_showConfTypeTableFieldName] = useTables typeNode.data[_showConfTypeChildFieldName] = (self[typeName]. childType) typeNode.data[_showConfTypeIconFieldName] = (self[typeName]. iconName) typeNode.data[_showConfTypeGenericFieldName] = (self[typeName]. genericType) if self[typeName].conditional: condition = self[typeName].conditional.conditionStr() typeNode.data[_showConfTypeConditionFieldName] = condition separator = self[typeName].outputSeparator typeNode.data[_showConfTypeSeparatorFieldName] = separator childLimit = ','.join(sorted(list(self[typeName].childTypeLimit))) typeNode.data[_showConfTypeChildLimitFieldName] = childLimit fieldSortKeyDict = {} fieldSortSet = False for field in self[typeName].fields(): fieldSortKeyDict[field.name] = repr(field.sortKeyNum) if field.sortKeyNum != 0: fieldSortSet = True if not fieldSortSet: sortField = list(self[typeName].fields())[0] fieldSortKeyDict[sortField.name] = repr(1) for field in self[typeName].fields(): fieldNode = treenode.TreeNode(fieldFormat) typeNode.childList.append(fieldNode) structure.addNodeDictRef(fieldNode) fieldNode.data[nodeformat.defaultFieldName] = field.name fieldNode.data[_showConfFieldTypeFieldName] = field.typeName fieldNode.data[_showConfFieldFormatFieldName] = field.format fieldNode.data[_showConfFieldPrefixFieldName] = field.prefix fieldNode.data[_showConfFieldSuffixFieldName] = field.suffix fieldNode.data[_showConfFieldInitFieldName] = field.initDefault numLines = repr(field.numLines) fieldNode.data[_showConfFieldLinesFieldName] = numLines sortKeyNum = fieldSortKeyDict[field.name] fieldNode.data[_showConfFieldSortKeyFieldName] = sortKeyNum sortKeyFwd = repr(field.sortKeyForward) fieldNode.data[_showConfFieldSortDirFieldName] = sortKeyFwd evalHtml = repr(field.evalHtml) fieldNode.data[_showConfFieldEvalHtmlFieldName] = evalHtml structure.generateSpots(None) return structure TreeLine-3.2.1/source/treeline.pro000066400000000000000000000027221506556630100170670ustar00rootroot00000000000000SOURCES = breadcrumbview.py \ conditional.py \ configdialog.py \ dataeditors.py \ dataeditview.py \ exports.py \ fieldformat.py \ genboolean.py \ gennumber.py \ globalref.py \ helpview.py \ icondict.py \ imports.py \ matheval.py \ miscdialogs.py \ nodeformat.py \ numbering.py \ optiondefaults.py \ options.py \ outputview.py \ p3.py \ printdata.py \ printdialogs.py \ recentfiles.py \ spellcheck.py \ titlelistview.py \ treeformats.py \ treeline.py \ treelocalcontrol.py \ treemaincontrol.py \ treemodel.py \ treenode.py \ treeoutput.py \ treeselection.py \ treespotlist.py \ treespot.py \ treestructure.py \ treeview.py \ treewindow.py \ undo.py \ urltools.py TRANSLATIONS = treeline_de.ts \ treeline_es.ts \ treeline_fr.ts \ treeline_it.ts \ treeline_pt.ts \ treeline_ru.ts \ treeline_xx.ts TreeLine-3.2.1/source/treeline.py000077500000000000000000000132121506556630100167160ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treeline.py, the main program file # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** __progname__ = 'TreeLine' __version__ = '3.2.1' __author__ = 'Doug Bell' docPath = None # modified by install script if required iconPath = None # modified by install script if required templatePath = None # modified by install script if required samplePath = None # modified by install script if required translationPath = 'translations' import sys import pathlib import os.path import argparse import locale import builtins from PyQt6.QtCore import QCoreApplication, QTranslator from PyQt6.QtWidgets import QApplication def loadTranslator(fileName, app): """Load and install qt translator, return True if sucessful. Arguments: fileName -- the translator file to load app -- the main QApplication """ translator = QTranslator(app) # use abspath() - pathlib's resolve() can be buggy with network drives modPath = pathlib.Path(os.path.abspath(sys.path[0])) if modPath.is_file(): modPath = modPath.parent # for frozen binary path = modPath / translationPath result = translator.load(fileName, str(path)) if not result: path = modPath.parent / translationPath result = translator.load(fileName, str(path)) if not result: path = modPath.parent / 'i18n' / translationPath result = translator.load(fileName, str(path)) if result: QCoreApplication.installTranslator(translator) return True else: print('Warning: translation file "{0}" could not be loaded'. format(fileName)) return False def setupTranslator(app, lang=''): """Set language, load translators and setup translator functions. Return the language setting Arguments: app -- the main QApplication lang -- language setting from the command line """ try: locale.setlocale(locale.LC_ALL, '') except locale.Error: pass if not lang: lang = os.environ.get('LC_MESSAGES', '') if not lang: lang = os.environ.get('LANG', '') if not lang: try: # This is deprecated, but getlocale() gives unusable # results (too verbose, not a language code???) lang = locale.getdefaultlocale()[0] except ValueError: pass if not lang: lang = '' numTranslators = 0 if lang and lang[:2] not in ['C', 'en']: numTranslators += loadTranslator('qt_{0}'.format(lang), app) numTranslators += loadTranslator('treeline_{0}'.format(lang), app) def translate(text, comment=''): """Translation function, sets context to calling module's filename. Arguments: text -- the text to be translated comment -- a comment used only as a guide for translators """ try: frame = sys._getframe(1) fileName = frame.f_code.co_filename finally: del frame context = pathlib.Path(fileName).stem return QCoreApplication.translate(context, text, comment) def markNoTranslate(text, comment=''): """Dummy translation function, only used to mark text. Arguments: text -- the text to be translated comment -- a comment used only as a guide for translators """ return text if numTranslators: builtins._ = translate else: builtins._ = markNoTranslate builtins.N_ = markNoTranslate return lang exceptDialog = None eventLoopRunning = False def handleException(excType, value, tb): """Handle uncaught exceptions, show debug info to the user. Called from sys.excepthook. Arguments: excType -- execption class value -- execption error text tb -- the traceback object """ import miscdialogs global exceptDialog exceptDialog = miscdialogs.ExceptionDialog(excType, value, tb) exceptDialog.show() global eventLoopRunning if not eventLoopRunning: eventLoopRunning = True QApplication.instance().exec() # start event loop if not running yet if __name__ == '__main__': """Main event loop for TreeLine """ app = QApplication(sys.argv) parser = argparse.ArgumentParser() parser.add_argument('--lang', help='language code for GUI translation') parser.add_argument('fileList', nargs='*', metavar='filename', help='input filename(s) to load') args = parser.parse_args() # use abspath() - pathlib's resolve() can be buggy with network drives pathObjects = [pathlib.Path(os.path.abspath(path)) for path in args.fileList] # must setup translator before any treeline module imports lang = setupTranslator(app, args.lang) import globalref globalref.localTextEncoding = locale.getpreferredencoding() globalref.lang = lang sys.excepthook = handleException import treemaincontrol treeMainControl = treemaincontrol.TreeMainControl(pathObjects) eventLoopRunning = True app.exec() TreeLine-3.2.1/source/treeline.spec000066400000000000000000000056361506556630100172300ustar00rootroot00000000000000# -*- mode: python -*- #****************************************************************************** # treeline.spec, provides settings for use with PyInstaller # # Creates a standalone windows executable # # Run the build process by running the command 'pyinstaller treeline.spec' # # If everything works well you should find a 'dist/treeline' subdirectory # that contains the files needed to run the application # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** block_cipher = None extraFiles = [('../doc', 'doc'), ('../icons', 'icons'), ('../samples', 'samples'), ('../source/*.py', 'source'), ('../source/*.pro', 'source'), ('../source/*.spec', 'source'), ('../templates', 'templates'), ('../translations', 'translations'), ('../win/*.*', '.')] a = Analysis(['treeline.py'], pathex=['C:\\git\\treeline\\devel\\source'], binaries=[], datas=extraFiles, hiddenimports=[], hookspath=[], runtime_hooks=[], excludes=[], win_no_prefer_redirects=False, win_private_assemblies=False, cipher=block_cipher, noarchive=False) pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) exe = EXE(pyz, a.scripts, [], exclude_binaries=True, name='treeline', debug=False, bootloader_ignore_signals=False, strip=False, upx=True, console=False, contents_directory='.', icon='..\\win\\treeline.ico') # a.binaries = a.binaries - TOC([('d3dcompiler_47.dll', None, None), # ('libcrypto-1_1.dll', None, None), # ('libeay32.dll', None, None), # ('libglesv2.dll', None, None), # ('libssl-1_1.dll', None, None), # ('opengl32sw.dll', None, None), # ('qt5dbus.dll', None, None), # ('qt5qml.dll', None, None), # ('qt5qmlmodels.dll', None, None), # ('qt5quick.dll', None, None), # ('qt5websockets.dll', None, None)]) coll = COLLECT(exe, a.binaries, a.zipfiles, a.datas, strip=False, upx=True, name='treeline') TreeLine-3.2.1/source/treelocalcontrol.py000066400000000000000000002323371506556630100204720ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treelocalcontrol.py, provides a class for the main tree commands # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import pathlib import json import os import sys import gzip import datetime import operator from itertools import chain from PyQt6.QtCore import QObject, QTimer, Qt, pyqtSignal from PyQt6.QtGui import QAction, QActionGroup from PyQt6.QtWidgets import (QApplication, QDialog, QFileDialog, QMenu, QMessageBox) import treemaincontrol import treestructure import treemodel import treeformats import treenode import treewindow import exports import miscdialogs import printdata import matheval import spellcheck import undo import p3 import globalref class TreeLocalControl(QObject): """Class to handle controls local to a model/view combination. Provides methods for all local controls and stores a model & windows. """ controlActivated = pyqtSignal(QObject) controlClosed = pyqtSignal(QObject) def __init__(self, allActions, fileObj=None, treeStruct=None, fileModTime=None, forceNewWindow=False, parent=None): """Initialize the local tree controls. Use an imported structure if given or open the file if path is given. Always creates a new window. Arguments: allActions -- a dict containing the upper level actions fileObj -- the path object or file object to open, if given treeStruct -- an imported tree structure file, if given fileModTime -- file modified time for external modification checks forceNewWindow -- if True, use a new window regardless of option parent -- a parent object if given """ super().__init__(parent) self.printData = printdata.PrintData(self) self.spellCheckLang = '' self.allActions = allActions.copy() self.setupActions() self.fileModTime = fileModTime self.filePathObj = (pathlib.Path(fileObj.name) if hasattr(fileObj, 'read') else fileObj) if treeStruct: self.structure = treeStruct elif fileObj: if hasattr(fileObj, 'read'): fileData = json.load(fileObj) else: with fileObj.open('r', encoding='utf-8') as f: fileData = json.load(f) self.structure = treestructure.TreeStructure(fileData) self.printData.readData(fileData['properties']) self.spellCheckLang = fileData['properties'].get('spellchk', '') else: self.structure = treestructure.TreeStructure(addDefaults=True) fileInfoFormat = self.structure.treeFormats.fileInfoFormat fileInfoFormat.updateFileInfo(self.filePathObj, self.structure.fileInfoNode) self.model = treemodel.TreeModel(self.structure) self.model.treeModified.connect(self.updateRightViews) self.modified = False self.imported = False self.compressed = False self.encrypted = False self.windowList = [] self.activeWindow = None self.findReplaceSpotRef = (None, 0) QApplication.clipboard().dataChanged.connect(self.updateCommandsAvail) self.structure.undoList = undo.UndoRedoList(self. allActions['EditUndo'], self) self.structure.redoList = undo.UndoRedoList(self. allActions['EditRedo'], self) self.structure.undoList.altListRef = self.structure.redoList self.structure.redoList.altListRef = self.structure.undoList self.autoSaveTimer = QTimer(self) self.autoSaveTimer.timeout.connect(self.autoSave) if not globalref.mainControl.activeControl: self.windowNew(offset=0) elif forceNewWindow or globalref.genOptions['OpenNewWindow']: self.windowNew() else: oldControl = globalref.mainControl.activeControl window = oldControl.activeWindow if len(oldControl.windowList) > 1: oldControl.windowList.remove(window) else: oldControl.controlClosed.emit(oldControl) window.resetTreeModel(self.model) self.setWindowSignals(window, True) window.updateActions(self.allActions) self.windowList.append(window) self.updateWindowCaptions() self.activeWindow = window if fileObj and self.structure.childRefErrorNodes: msg = _('Warning - file corruption!\n' 'Skipped bad child references in the following nodes:') for node in self.structure.childRefErrorNodes: msg += '\n "{}"'.format(node.title()) QMessageBox.warning(self.activeWindow, 'TreeLine', msg) self.structure.childRefErrorNodes = [] def setWindowSignals(self, window, removeOld=False): """Setup signals between the window and this controller. Arguments: window -- the window to link removeOld -- if True, remove old signals """ if removeOld: window.selectChanged.disconnect() window.nodeModified.disconnect() window.treeModified.disconnect() window.winActivated.disconnect() window.winClosing.disconnect() window.selectChanged.connect(self.updateCommandsAvail) window.nodeModified.connect(self.updateTreeNode) window.treeModified.connect(self.updateTree) window.winActivated.connect(self.setActiveWin) window.winClosing.connect(self.checkWindowClose) window.setExternalSignals() def updateTreeNode(self, node, setModified=True): """Update the full tree in all windows. Also update right views in secondary windows. Arguments: node -- the node to be updated setModified -- if True, set the modified flag for this file """ if node.setConditionalType(self.structure): self.activeWindow.updateRightViews(outputOnly=True) if (self.structure.treeFormats.mathFieldRefDict and node.updateNodeMathFields(self.structure.treeFormats)): self.activeWindow.updateRightViews(outputOnly=True) if globalref.genOptions['ShowMath']: self.activeWindow.refreshDataEditViews() for window in self.windowList: window.updateTreeNode(node) if window.treeFilterView: window.treeFilterView.updateItem(node) if setModified: self.setModified() def updateTree(self, setModified=True): """Update the full tree in all windows. Also update right views in secondary windows. Arguments: setModified -- if True, set the modified flag for this file """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) typeChanges = 0 if self.structure.treeFormats.conditionalTypes: for node in self.structure.childList: typeChanges += node.setDescendantConditionalTypes(self. structure) self.updateAllMathFields() for window in self.windowList: window.updateTree() if window != self.activeWindow or typeChanges: window.updateRightViews() if window.treeFilterView: window.treeFilterView.updateContents() if setModified: self.setModified() QApplication.restoreOverrideCursor() def updateRightViews(self, setModified=False, otherTrees=False): """Update the right-hand views in all windows. Arguments: setModified -- if True, set the modified flag for this file otherTrees -- if True, also update trees in non-active windows """ for window in self.windowList: window.updateRightViews() if otherTrees and window != self.activeWindow: window.updateTree() if setModified: self.setModified() def updateAll(self, setModified=True): """Update the full tree and right-hand views in all windows. Arguments: setModified -- if True, set the modified flag for this file """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if self.structure.treeFormats.conditionalTypes: for node in self.structure.childList: node.setDescendantConditionalTypes(self.structure) self.updateAllMathFields() for window in self.windowList: window.updateTree() if window.treeFilterView: window.treeFilterView.updateContents() window.updateRightViews() self.updateCommandsAvail() if setModified: self.setModified() # self.structure.debugCheck() QApplication.restoreOverrideCursor() def updateAllMathFields(self): """Recalculate all math fields in the entire tree. """ for eqnRefDict in self.structure.treeFormats.mathLevelList: if list(eqnRefDict.values())[0][0].evalDirection != (matheval. EvalDir. upward): for node in self.structure.descendantGen(): for eqnRef in eqnRefDict.get(node.formatRef.name, []): node.data[eqnRef.eqnField.name] = (eqnRef.eqnField. equationValue(node)) else: spot = self.structure.structSpot().lastDescendantSpot() while spot: node = spot.nodeRef for eqnRef in eqnRefDict.get(node.formatRef.name, []): node.data[eqnRef.eqnField.name] = (eqnRef.eqnField. equationValue(node)) spot = spot.prevTreeSpot() def updateCommandsAvail(self): """Set commands available based on node selections. """ selSpots = self.currentSelectionModel().selectedSpots() hasSelect = len(selSpots) > 0 rootSpots = [spot for spot in selSpots if not spot.parentSpot.parentSpot] hasPrevSibling = (len(selSpots) and None not in [spot.prevSiblingSpot() for spot in selSpots]) hasNextSibling = (len(selSpots) and None not in [spot.nextSiblingSpot() for spot in selSpots]) hasChildren = (sum([len(spot.nodeRef.childList) for spot in selSpots]) > 0) mime = QApplication.clipboard().mimeData() hasData = len(mime.data('application/json')) > 0 hasText = len(mime.data('text/plain')) > 0 self.allActions['EditPaste'].setEnabled(hasData or hasText) self.allActions['EditPasteChild'].setEnabled(hasData) self.allActions['EditPasteBefore'].setEnabled(hasData and hasSelect) self.allActions['EditPasteAfter'].setEnabled(hasData and hasSelect) self.allActions['EditPasteCloneChild'].setEnabled(hasData) self.allActions['EditPasteCloneBefore'].setEnabled(hasData and hasSelect) self.allActions['EditPasteCloneAfter'].setEnabled(hasData and hasSelect) self.allActions['NodeRename'].setEnabled(len(selSpots) == 1) self.allActions['NodeInsertBefore'].setEnabled(hasSelect) self.allActions['NodeInsertAfter'].setEnabled(hasSelect) self.allActions['NodeDelete'].setEnabled(hasSelect and len(rootSpots) < len(self.structure.childList)) self.allActions['NodeIndent'].setEnabled(hasPrevSibling) self.allActions['NodeUnindent'].setEnabled(hasSelect and len(rootSpots) == 0) self.allActions['NodeMoveUp'].setEnabled(hasPrevSibling) self.allActions['NodeMoveDown'].setEnabled(hasNextSibling) self.allActions['NodeMoveFirst'].setEnabled(hasPrevSibling) self.allActions['NodeMoveLast'].setEnabled(hasNextSibling) self.allActions['DataNodeType'].parent().setEnabled(hasSelect) self.allActions['DataFlatCategory'].setEnabled(hasChildren) self.allActions['DataAddCategory'].setEnabled(hasChildren) self.allActions['DataSwapCategory'].setEnabled(hasChildren) if self.activeWindow.treeFilterView: self.allActions['NodeInsertBefore'].setEnabled(False) self.allActions['NodeInsertAfter'].setEnabled(False) self.allActions['NodeAddChild'].setEnabled(False) self.allActions['NodeIndent'].setEnabled(False) self.allActions['NodeUnindent'].setEnabled(False) self.allActions['NodeMoveUp'].setEnabled(False) self.allActions['NodeMoveDown'].setEnabled(False) self.allActions['NodeMoveFirst'].setEnabled(False) self.allActions['NodeMoveLast'].setEnabled(False) else: self.allActions['NodeAddChild'].setEnabled(True) self.activeWindow.updateCommandsAvail() def updateWindowCaptions(self): """Update the caption for all windows. """ for window in self.windowList: window.setCaption(self.filePathObj, self.modified) def setModified(self, modified=True): """Set the modified flag on this file and update commands available. Arguments: modified -- the modified state to set """ if modified != self.modified: self.modified = modified self.allActions['FileSave'].setEnabled(modified) self.updateWindowCaptions() self.resetAutoSave() def expandRootNodes(self, maxNum=5): """Expand root node if there are fewer than the maximum. Arguments: maxNum -- only expand if there are fewer root nodes than this. """ if len(self.structure.childList) < maxNum: treeView = self.activeWindow.treeView for spot in self.structure.rootSpots(): treeView.expandSpot(spot) def selectRootSpot(self): """Select the first root spot in the tree. Does not signal an update. """ self.currentSelectionModel().selectSpots([self.structure. rootSpots()[0]], False) def currentSelectionModel(self): """Return the current tree's selection model. """ return self.activeWindow.treeView.selectionModel() def setActiveWin(self, window): """When a window is activated, stores it and emits a signal. Arguments: window -- the new active window """ self.activeWindow = window self.controlActivated.emit(self) self.updateCommandsAvail() def checkWindowClose(self, window): """Check for modified files and delete ref when a window is closing. Arguments: window -- the window being closed """ if len(self.windowList) > 1: self.windowList.remove(window) # set active to one not closing to avoid errors while changing self.activeWindow = self.windowList[0] window.allowCloseFlag = True elif self.checkSaveChanges(): window.allowCloseFlag = True self.controlClosed.emit(self) else: window.allowCloseFlag = False def checkSaveChanges(self): """Ask for save if doc modified, return True if OK to continue. Save this doc if directed. Return True if not modified, if saved or if discarded. Return False on cancel. """ if not self.modified or len(self.windowList) > 1: return True promptText = (_('Save changes to {}?').format(self.filePathObj) if self.filePathObj else _('Save changes?')) ans = QMessageBox.information(self.activeWindow, 'TreeLine', promptText, QMessageBox.StandardButton.Save | QMessageBox.StandardButton.Discard | QMessageBox.StandardButton.Cancel, QMessageBox.StandardButton.Save) if ans == QMessageBox.StandardButton.Save: self.fileSave() elif ans == QMessageBox.StandardButton.Cancel: return False else: self.deleteAutoSaveFile() return True def closeWindows(self): """Close this control's windows prior to quiting the application. """ for window in self.windowList: window.close() def autoSave(self): """Save a backup file if appropriate. Called from the timer. """ if self.filePathObj and not self.imported: self.fileSave(True) def resetAutoSave(self): """Start or stop the auto-save timer based on file modified status. Also delete old autosave files if file becomes unmodified. """ self.autoSaveTimer.stop() minutes = globalref.genOptions['AutoSaveMinutes'] if minutes and self.modified: self.autoSaveTimer.start(60000 * minutes) else: self.deleteAutoSaveFile() def deleteAutoSaveFile(self): """Delete an auto save file if it exists. """ filePath = pathlib.Path(str(self.filePathObj) + '~') if self.filePathObj and filePath.is_file(): try: filePath.unlink() except OSError: QMessageBox.warning(self.activeWindow, 'TreeLine', _('Error - could not delete backup file {}'). format(filePath)) def windowActions(self, startNum=1, active=False): """Return a list of window menu actions to select this file's windows. Arguments: startNum -- where to start numbering the action names active -- if True, activate the current active window """ actions = [] maxActionPathLength = 30 abbrevPath = str(self.filePathObj) if len(abbrevPath) > maxActionPathLength: truncLength = maxActionPathLength - 3 pos = abbrevPath.find(os.sep, len(abbrevPath) - truncLength) if pos < 0: pos = len(abbrevPath) - truncLength abbrevPath = '...' + abbrevPath[pos:] for window in self.windowList: action = QAction('&{0:d} {1}'.format(startNum, abbrevPath), self, statusTip=str(self.filePathObj), checkable=True) action.triggered.connect(window.activateAndRaise) if active and window == self.activeWindow: action.setChecked(True) actions.append(action) startNum += 1 return actions def setupActions(self): """Add the actions for contols at the local level. These actions affect an individual file, possibly in multiple windows. """ localActions = {} fileSaveAct = QAction(_('&Save'), self, toolTip=_('Save File'), statusTip=_('Save the current file')) fileSaveAct.setEnabled(False) fileSaveAct.triggered.connect(self.fileSave) localActions['FileSave'] = fileSaveAct fileSaveAsAct = QAction(_('Save &As...'), self, statusTip=_('Save the file with a new name')) fileSaveAsAct.triggered.connect(self.fileSaveAs) localActions['FileSaveAs'] = fileSaveAsAct fileExportAct = QAction(_('&Export...'), self, statusTip=_('Export the file in various other formats')) fileExportAct.triggered.connect(self.fileExport) localActions['FileExport'] = fileExportAct filePropertiesAct = QAction(_('Prop&erties...'), self, statusTip=_('Set file parameters like compression and encryption')) filePropertiesAct.triggered.connect(self.fileProperties) localActions['FileProperties'] = filePropertiesAct filePrintSetupAct = QAction(_('P&rint Setup...'), self, statusTip=_('Set margins, page size and other printing options')) filePrintSetupAct.triggered.connect(self.printData.printSetup) localActions['FilePrintSetup'] = filePrintSetupAct filePrintPreviewAct = QAction(_('Print Pre&view...'), self, statusTip=_('Show a preview of printing results')) filePrintPreviewAct.triggered.connect(self.printData.printPreview) localActions['FilePrintPreview'] = filePrintPreviewAct filePrintAct = QAction(_('&Print...'), self, statusTip=_('Print tree output based on current options')) filePrintAct.triggered.connect(self.printData.filePrint) localActions['FilePrint'] = filePrintAct filePrintPdfAct = QAction(_('Print &to PDF...'), self, statusTip=_('Export to PDF with current printing options')) filePrintPdfAct.triggered.connect(self.printData.filePrintPdf) localActions['FilePrintPdf'] = filePrintPdfAct editUndoAct = QAction(_('&Undo'), self, statusTip=_('Undo the previous action')) editUndoAct.triggered.connect(self.editUndo) localActions['EditUndo'] = editUndoAct editRedoAct = QAction(_('&Redo'), self, statusTip=_('Redo the previous undo')) editRedoAct.triggered.connect(self.editRedo) localActions['EditRedo'] = editRedoAct editCutAct = QAction(_('Cu&t'), self, statusTip=_('Cut the branch or text to the clipboard')) editCutAct.triggered.connect(self.editCut) localActions['EditCut'] = editCutAct editCopyAct = QAction(_('&Copy'), self, statusTip=_('Copy the branch or text to the clipboard')) editCopyAct.triggered.connect(self.editCopy) localActions['EditCopy'] = editCopyAct editPasteAct = QAction(_('&Paste'), self, statusTip=_('Paste nodes or text from the clipboard')) editPasteAct.triggered.connect(self.editPaste) localActions['EditPaste'] = editPasteAct editPastePlainAct = QAction(_('Pa&ste Plain Text'), self, statusTip=_('Paste non-formatted text from the clipboard')) editPastePlainAct.setEnabled(False) localActions['EditPastePlain'] = editPastePlainAct editPasteChildAct = QAction(_('Paste C&hild'), self, statusTip=_('Paste a child node from the clipboard')) editPasteChildAct.triggered.connect(self.editPasteChild) localActions['EditPasteChild'] = editPasteChildAct editPasteBeforeAct = QAction(_('Paste Sibling &Before'), self, statusTip=_('Paste a sibling before selection')) editPasteBeforeAct.triggered.connect(self.editPasteBefore) localActions['EditPasteBefore'] = editPasteBeforeAct editPasteAfterAct = QAction(_('Paste Sibling &After'), self, statusTip=_('Paste a sibling after selection')) editPasteAfterAct.triggered.connect(self.editPasteAfter) localActions['EditPasteAfter'] = editPasteAfterAct editPasteCloneChildAct = QAction(_('Paste Cl&oned Child'), self, statusTip=_('Paste a child clone from the clipboard')) editPasteCloneChildAct.triggered.connect(self.editPasteCloneChild) localActions['EditPasteCloneChild'] = editPasteCloneChildAct editPasteCloneBeforeAct = QAction(_('Paste Clo&ned Sibling Before'), self, statusTip=_('Paste a sibling clone before selection')) editPasteCloneBeforeAct.triggered.connect(self.editPasteCloneBefore) localActions['EditPasteCloneBefore'] = editPasteCloneBeforeAct editPasteCloneAfterAct = QAction(_('Paste Clone&d Sibling After'), self, statusTip=_('Paste a sibling clone after selection')) editPasteCloneAfterAct.triggered.connect(self.editPasteCloneAfter) localActions['EditPasteCloneAfter'] = editPasteCloneAfterAct nodeRenameAct = QAction(_('&Rename'), self, statusTip=_('Rename the current tree entry title')) nodeRenameAct.triggered.connect(self.nodeRename) localActions['NodeRename'] = nodeRenameAct nodeAddChildAct = QAction(_('Add &Child'), self, statusTip=_('Add new child to selected parent')) nodeAddChildAct.triggered.connect(self.nodeAddChild) localActions['NodeAddChild'] = nodeAddChildAct nodeInBeforeAct = QAction(_('Insert Sibling &Before'), self, statusTip=_('Insert new sibling before selection')) nodeInBeforeAct.triggered.connect(self.nodeInBefore) localActions['NodeInsertBefore'] = nodeInBeforeAct nodeInAfterAct = QAction(_('Insert Sibling &After'), self, statusTip=_('Insert new sibling after selection')) nodeInAfterAct.triggered.connect(self.nodeInAfter) localActions['NodeInsertAfter'] = nodeInAfterAct nodeDeleteAct = QAction(_('&Delete Node'), self, statusTip=_('Delete the selected nodes')) nodeDeleteAct.triggered.connect(self.nodeDelete) localActions['NodeDelete'] = nodeDeleteAct nodeIndentAct = QAction(_('&Indent Node'), self, statusTip=_('Indent the selected nodes')) nodeIndentAct.triggered.connect(self.nodeIndent) localActions['NodeIndent'] = nodeIndentAct nodeUnindentAct = QAction(_('&Unindent Node'), self, statusTip=_('Unindent the selected nodes')) nodeUnindentAct.triggered.connect(self.nodeUnindent) localActions['NodeUnindent'] = nodeUnindentAct nodeMoveUpAct = QAction(_('&Move Up'), self, statusTip=_('Move the selected nodes up')) nodeMoveUpAct.triggered.connect(self.nodeMoveUp) localActions['NodeMoveUp'] = nodeMoveUpAct nodeMoveDownAct = QAction(_('M&ove Down'), self, statusTip=_('Move the selected nodes down')) nodeMoveDownAct.triggered.connect(self.nodeMoveDown) localActions['NodeMoveDown'] = nodeMoveDownAct nodeMoveFirstAct = QAction(_('Move &First'), self, statusTip=_('Move the selected nodes to be the first children')) nodeMoveFirstAct.triggered.connect(self.nodeMoveFirst) localActions['NodeMoveFirst'] = nodeMoveFirstAct nodeMoveLastAct = QAction(_('Move &Last'), self, statusTip=_('Move the selected nodes to be the last children')) nodeMoveLastAct.triggered.connect(self.nodeMoveLast) localActions['NodeMoveLast'] = nodeMoveLastAct title = _('&Set Node Type') key = globalref.keyboardOptions['DataNodeType'] if not key.isEmpty(): title = '{0} ({1})'.format(title, key.toString()) self.typeSubMenu = QMenu(title, statusTip=_('Set the node type for selected nodes')) self.typeSubMenu.aboutToShow.connect(self.loadTypeSubMenu) self.typeSubMenu.triggered.connect(self.dataSetType) typeContextMenuAct = QAction(_('Set Node Type'), self.typeSubMenu) typeContextMenuAct.triggered.connect(self.showTypeContextMenu) localActions['DataNodeType'] = typeContextMenuAct dataCopyTypeAct = QAction(_('Copy Types from &File...'), self, statusTip=_('Copy the configuration from another TreeLine file')) dataCopyTypeAct.triggered.connect(self.dataCopyType) localActions['DataCopyType'] = dataCopyTypeAct dataRegenRefsAct = QAction(_('&Regenerate References'), self, statusTip=_('Force update of all conditional types & math fields')) dataRegenRefsAct.triggered.connect(self.dataRegenRefs) localActions['DataRegenRefs'] = dataRegenRefsAct dataCloneMatchesAct = QAction(_('Clone All &Matched Nodes'), self, statusTip=_('Convert all matching nodes into clones')) dataCloneMatchesAct.triggered.connect(self.dataCloneMatches) localActions['DataCloneMatches'] = dataCloneMatchesAct dataDetachClonesAct = QAction(_('&Detach Clones'), self, statusTip=_('Detach all cloned nodes in current branches')) dataDetachClonesAct.triggered.connect(self.dataDetachClones) localActions['DataDetachClones'] = dataDetachClonesAct dataFlatCatAct = QAction(_('Flatten &by Category'), self, statusTip=_('Collapse descendants by merging fields')) dataFlatCatAct.triggered.connect(self.dataFlatCategory) localActions['DataFlatCategory'] = dataFlatCatAct dataAddCatAct = QAction(_('Add Category &Level...'), self, statusTip=_('Insert category nodes above children')) dataAddCatAct.triggered.connect(self.dataAddCategory) localActions['DataAddCategory'] = dataAddCatAct dataSwapCatAct = QAction(_('S&wap Category Levels'), self, statusTip=_('Swap child and grandchild category nodes')) dataSwapCatAct.triggered.connect(self.dataSwapCategory) localActions['DataSwapCategory'] = dataSwapCatAct toolsSpellCheckAct = QAction(_('&Spell Check...'), self, statusTip=_('Spell check the tree\'s text data')) toolsSpellCheckAct.triggered.connect(self.toolsSpellCheck) localActions['ToolsSpellCheck'] = toolsSpellCheckAct formatBoldAct = QAction(_('&Bold Font'), self, statusTip=_('Set the current or selected font to bold'), checkable=True) formatBoldAct.setEnabled(False) localActions['FormatBoldFont'] = formatBoldAct formatItalicAct = QAction(_('&Italic Font'), self, statusTip=_('Set the current or selected font to italic'), checkable=True) formatItalicAct.setEnabled(False) localActions['FormatItalicFont'] = formatItalicAct formatUnderlineAct = QAction(_('U&nderline Font'), self, statusTip=_('Set the current or selected font to underline'), checkable=True) formatUnderlineAct.setEnabled(False) localActions['FormatUnderlineFont'] = formatUnderlineAct formatStrikethroughAct = QAction(_('St&rikethrough Font'), self, statusTip=_('Set the current or selected font to strikethough'), checkable=True) formatStrikethroughAct.setEnabled(False) localActions['FormatStrikethroughFont'] = formatStrikethroughAct title = _('&Font Size') key = globalref.keyboardOptions['FormatFontSize'] if not key.isEmpty(): title = '{0} ({1})'.format(title, key.toString()) self.fontSizeSubMenu = QMenu(title, statusTip=_('Set size of the current or selected text')) sizeActions = QActionGroup(self) for size in (_('Small'), _('Default'), _('Large'), _('Larger'), _('Largest')): action = QAction(size, sizeActions) action.setCheckable(True) self.fontSizeSubMenu.addActions(sizeActions.actions()) self.fontSizeSubMenu.setEnabled(False) fontSizeContextMenuAct = QAction(_('Set Font Size'), self.fontSizeSubMenu) localActions['FormatFontSize'] = fontSizeContextMenuAct formatColorAct = QAction(_('Font C&olor...'), self, statusTip=_('Set the color of the current or selected text')) formatColorAct.setEnabled(False) localActions['FormatFontColor'] = formatColorAct formatExtLinkAct = QAction(_('&External Link...'), self, statusTip=_('Add or modify an extrnal web link')) formatExtLinkAct.setEnabled(False) localActions['FormatExtLink'] = formatExtLinkAct formatIntLinkAct = QAction(_('Internal &Link...'), self, statusTip=_('Add or modify an internal node link')) formatIntLinkAct.setEnabled(False) localActions['FormatIntLink'] = formatIntLinkAct formatInsDateAct = QAction(_('Insert &Date'), self, statusTip=_('Insert current date as text')) formatInsDateAct.setEnabled(False) localActions['FormatInsertDate'] = formatInsDateAct formatClearFormatAct = QAction(_('Clear For&matting'), self, statusTip=_('Clear current or selected text formatting')) formatClearFormatAct.setEnabled(False) localActions['FormatClearFormat'] = formatClearFormatAct winNewAct = QAction(_('&New Window'), self, statusTip=_('Open a new window for the same file')) winNewAct.triggered.connect(self.windowNew) localActions['WinNewWindow'] = winNewAct for name, action in localActions.items(): icon = globalref.toolIcons.getIcon(name.lower()) if icon: action.setIcon(icon) key = globalref.keyboardOptions[name] if not key.isEmpty(): action.setShortcut(key) typeIcon = globalref.toolIcons.getIcon('DataNodeType'.lower()) if typeIcon: self.typeSubMenu.setIcon(typeIcon) fontIcon = globalref.toolIcons.getIcon('FormatFontSize'.lower()) if fontIcon: self.fontSizeSubMenu.setIcon(fontIcon) self.allActions.update(localActions) def fileSave(self, backupFile=False): """Save the currently active file. Arguments: backupFile -- if True, write auto-save backup file instead """ if not self.filePathObj or self.imported: self.fileSaveAs() return if not backupFile and self.fileModTime: fileSeconds = self.filePathObj.stat().st_mtime storedSeconds = self.fileModTime.timestamp() # check for an external file mod with a 10 second margin if fileSeconds > storedSeconds + 10: dialog = miscdialogs.ExtModDialog(datetime.datetime. fromtimestamp(fileSeconds), self.activeWindow) if dialog.exec() != QDialog.DialogCode.Accepted: # user cancelled the save return QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) savePathObj = self.filePathObj if backupFile: savePathObj = pathlib.Path(str(savePathObj) + '~') else: self.structure.purgeOldFieldData() fileData = self.structure.fileData() fileData['properties'].update(self.printData.fileData()) if self.spellCheckLang: fileData['properties']['spellchk'] = self.spellCheckLang if not self.compressed and not self.encrypted: indent = 3 if globalref.genOptions['PrettyPrint'] else 0 try: with savePathObj.open('w', encoding='utf-8', newline='\n') as f: json.dump(fileData, f, indent=indent, sort_keys=True) except IOError: QApplication.restoreOverrideCursor() QMessageBox.warning(self.activeWindow, 'TreeLine', _('Error - could not write to {}'). format(savePathObj)) return else: data = json.dumps(fileData, indent=0, sort_keys=True).encode() if self.compressed: data = gzip.compress(data) if self.encrypted: password = (globalref.mainControl.passwords. get(self.filePathObj, '')) if not password: QApplication.restoreOverrideCursor() dialog = miscdialogs.PasswordDialog(True, '', self.activeWindow) if dialog.exec() != QDialog.DialogCode.Accepted: return QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) password = dialog.password if miscdialogs.PasswordDialog.remember: globalref.mainControl.passwords[self. filePathObj] = password data = (treemaincontrol.encryptPrefix + p3.p3_encrypt(data, password.encode())) try: with savePathObj.open('wb') as f: f.write(data) except IOError: QApplication.restoreOverrideCursor() QMessageBox.warning(self.activeWindow, 'TreeLine', _('Error - could not write to {}'). format(savePathObj)) return QApplication.restoreOverrideCursor() if not backupFile: self.fileModTime = datetime.datetime.now() fileInfoFormat = self.structure.treeFormats.fileInfoFormat fileInfoFormat.updateFileInfo(self.filePathObj, self.structure.fileInfoNode) self.setModified(False) self.imported = False self.activeWindow.statusBar().showMessage(_('File saved'), 3000) def fileSaveAs(self): """Prompt for a new file name and save the file. """ oldPathObj = self.filePathObj oldModifiedFlag = self.modified oldImportFlag = self.imported self.modified = True self.imported = False filters = ';;'.join((globalref.fileFilters['trlnsave'], globalref.fileFilters['trlngz'], globalref.fileFilters['trlnenc'])) initFilter = globalref.fileFilters['trlnsave'] defaultPathObj = globalref.mainControl.defaultPathObj() if defaultPathObj.is_file(): defaultPathObj = defaultPathObj.with_suffix('.trln') newPath, selectFilter = (QFileDialog. getSaveFileName(self.activeWindow, _('TreeLine - Save As'), str(defaultPathObj), filters, initFilter)) if newPath: self.fileModTime = None self.filePathObj = pathlib.Path(newPath) if not self.filePathObj.suffix: self.filePathObj = self.filePathObj.with_suffix('.trln') if selectFilter != initFilter: self.compressed = (selectFilter == globalref.fileFilters['trlngz']) self.encrypted = (selectFilter == globalref.fileFilters['trlnenc']) self.fileSave() if not self.modified: globalref.mainControl.recentFiles.addItem(self.filePathObj) self.updateWindowCaptions() return self.filePathObj = oldPathObj self.modified = oldModifiedFlag self.imported = oldImportFlag def fileExport(self): """Export the file in various other formats. """ exportControl = exports.ExportControl(self.structure, self.currentSelectionModel(), globalref.mainControl. defaultPathObj(), self.printData) try: exportControl.interactiveExport() except IOError: QApplication.restoreOverrideCursor() QMessageBox.warning(self.activeWindow, 'TreeLine', _('Error - could not write to file')) def fileProperties(self): """Show dialog to set file parameters like compression and encryption. """ origZeroBlanks = self.structure.mathZeroBlanks dialog = miscdialogs.FilePropertiesDialog(self, self.activeWindow) if dialog.exec() == QDialog.DialogCode.Accepted: self.setModified() if self.structure.mathZeroBlanks != origZeroBlanks: self.updateAll(False) def editUndo(self): """Undo the previous action and update the views. """ self.structure.undoList.undo() self.updateAll(False) def editRedo(self): """Redo the previous undo and update the views. """ self.structure.redoList.undo() self.updateAll(False) def editCut(self): """Cut the branch or text to the clipboard. """ widget = QApplication.focusWidget() try: if widget.hasSelectedText(): widget.cut() return except AttributeError: pass self.currentSelectionModel().copySelectedNodes() selSpots = self.currentSelectionModel().selectedSpots() rootSpots = [spot for spot in selSpots if not spot.parentSpot.parentSpot] if selSpots and len(rootSpots) < len(self.structure.childList): self.nodeDelete() def editCopy(self): """Copy the branch or text to the clipboard. Copy from any selection in non-focused output view, or copy from any focused editor, or copy from tree. """ widgets = [QApplication.focusWidget()] splitter = self.activeWindow.rightTabs.currentWidget() if splitter == self.activeWindow.outputSplitter: widgets[0:0] = [splitter.widget(0), splitter.widget(1)] for widget in widgets: try: if widget.hasSelectedText(): widget.copy() return except AttributeError: pass self.currentSelectionModel().copySelectedNodes() def editPaste(self): """Paste nodes or text from the clipboard. """ if self.activeWindow.treeView.hasFocus(): self.editPasteChild() else: widget = QApplication.focusWidget() try: widget.paste() except AttributeError: pass def editPasteChild(self): """Paste a child node from the clipboard. """ if (self.currentSelectionModel().selectedSpots(). pasteChild(self.structure, self.activeWindow.treeView)): self.updateAll() globalref.mainControl.updateConfigDialog() def editPasteBefore(self): """Paste a sibling before selection. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([spot.parentSpot.childSpots() for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) if selSpots.pasteSibling(self.structure): treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots(selSpots, False) self.updateAll() globalref.mainControl.updateConfigDialog() def editPasteAfter(self): """Paste a sibling after selection. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([spot.parentSpot.childSpots() for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) if selSpots.pasteSibling(self.structure, False): treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots(selSpots, False) self.updateAll() globalref.mainControl.updateConfigDialog() def editPasteCloneChild(self): """Paste a child clone from the clipboard. """ if (self.currentSelectionModel().selectedSpots(). pasteCloneChild(self.structure, self.activeWindow.treeView)): self.updateAll() def editPasteCloneBefore(self): """Paste a sibling clone before selection. """ selSpots = self.currentSelectionModel().selectedSpots() if selSpots.pasteCloneSibling(self.structure): self.currentSelectionModel().selectSpots(selSpots, False) self.updateAll() def editPasteCloneAfter(self): """Paste a sibling clone after selection. """ selSpots = self.currentSelectionModel().selectedSpots() if selSpots.pasteCloneSibling(self.structure, False): self.currentSelectionModel().selectSpots(selSpots, False) self.updateAll() def nodeRename(self): """Start the rename editor in the selected tree node. """ if self.activeWindow.treeFilterView: self.activeWindow.treeFilterView.editItem(self.activeWindow. treeFilterView. currentItem()) else: self.activeWindow.treeView.endEditing() self.activeWindow.treeView.edit(self.currentSelectionModel(). currentIndex()) def nodeAddChild(self): """Add new child to selected parent. """ self.activeWindow.treeView.endEditing() selSpots = self.currentSelectionModel().selectedSpots() newSpots = selSpots.addChild(self.structure, self.activeWindow.treeView) self.updateAll() if globalref.genOptions['RenameNewNodes']: self.currentSelectionModel().selectSpots(newSpots) if len(newSpots) == 1: self.activeWindow.treeView.edit(newSpots[0].index(self.model)) def nodeInBefore(self): """Insert new sibling before selection. """ treeView = self.activeWindow.treeView treeView.endEditing() selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([spot.parentSpot.childSpots() for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) newSpots = selSpots.insertSibling(self.structure) treeView.restoreExpandState(expandState) self.updateAll() if globalref.genOptions['RenameNewNodes']: self.currentSelectionModel().selectSpots(newSpots) if len(newSpots) == 1: treeView.edit(newSpots[0].index(self.model)) def nodeInAfter(self): """Insert new sibling after selection. """ treeView = self.activeWindow.treeView treeView.endEditing() selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([spot.parentSpot.childSpots() for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) newSpots = selSpots.insertSibling(self.structure, False) treeView.restoreExpandState(expandState) self.updateAll() if globalref.genOptions['RenameNewNodes']: self.currentSelectionModel().selectSpots(newSpots) if len(newSpots) == 1: treeView.edit(newSpots[0].index(self.model)) def nodeDelete(self): """Delete the selected nodes. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedBranchSpots() if selSpots: # collapse deleted items to avoid crash for spot in selSpots: treeView.collapseSpot(spot) # clear hover to avoid crash if deleted child item was hovered over self.activeWindow.treeView.clearHover() # clear selection to avoid invalid multiple selection bug self.currentSelectionModel().selectSpots([], False) # clear selections in other windows that are about to be deleted for window in self.windowList: if window != self.activeWindow: selectModel = window.treeView.selectionModel() ancestors = set() for spot in selectModel.selectedBranchSpots(): ancestors.update(set(spot.spotChain())) if ancestors & set(selSpots): selectModel.selectSpots([], False) saveSpots = chain.from_iterable([spot.parentSpot.childSpots() for spot in selSpots]) saveSpots = set(saveSpots) - set(selSpots) expandState = treeView.savedExpandState(saveSpots) nextSel = selSpots.delete(self.structure) treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots([nextSel]) self.updateAll() def nodeIndent(self): """Indent the selected nodes. Makes them children of their previous siblings. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([spot.parentSpot.childSpots() for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) newSpots = selSpots.indent(self.structure) treeView.restoreExpandState(expandState) for spot in selSpots: treeView.expandSpot(spot.parentSpot) self.currentSelectionModel().selectSpots(newSpots, False) self.updateAll() def nodeUnindent(self): """Unindent the selected nodes. Makes them their parent's next sibling. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([spot.parentSpot.childSpots() for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) newSpots = selSpots.unindent(self.structure) treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots(newSpots, False) self.updateAll() def nodeMoveUp(self): """Move the selected nodes upward in the sibling list. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([(spot, spot.prevSiblingSpot()) for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) selSpots.move(self.structure) self.updateAll() treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots(selSpots) def nodeMoveDown(self): """Move the selected nodes downward in the sibling list. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([(spot, spot.nextSiblingSpot()) for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) selSpots.move(self.structure, False) self.updateAll() treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots(selSpots) def nodeMoveFirst(self): """Move the selected nodes to be the first children. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([(spot, spot.parentSpot.childSpots()[0]) for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) selSpots.moveToEnd(self.structure) self.updateAll() treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots(selSpots) def nodeMoveLast(self): """Move the selected nodes to be the last children. """ treeView = self.activeWindow.treeView selSpots = self.currentSelectionModel().selectedSpots() saveSpots = chain.from_iterable([(spot, spot.parentSpot.childSpots()[-1]) for spot in selSpots]) expandState = treeView.savedExpandState(saveSpots) selSpots.moveToEnd(self.structure, False) self.updateAll() treeView.restoreExpandState(expandState) self.currentSelectionModel().selectSpots(selSpots) def dataSetType(self, action): """Change the type of selected nodes based on a menu selection. Arguments: action -- the menu action containing the new type name """ newType = action.toolTip() # gives menu name without the accelerator nodes = [node for node in self.currentSelectionModel().selectedNodes() if node.formatRef.name != newType] if nodes: undo.TypeUndo(self.structure.undoList, nodes) for node in nodes: node.changeDataType(self.structure.treeFormats[newType]) self.updateAll() def loadTypeSubMenu(self): """Update type select submenu with type names and check marks. """ selectTypeNames = set() typeLimitNames = set() for node in self.currentSelectionModel().selectedNodes(): selectTypeNames.add(node.formatRef.name) if typeLimitNames is not None: for parent in node.parents(): limit = (parent.formatRef.childTypeLimit if parent.formatRef else None) if (not limit or (typeLimitNames and limit != typeLimitNames)): typeLimitNames = None elif typeLimitNames is not None: typeLimitNames = limit if typeLimitNames: typeNames = sorted(list(typeLimitNames)) else: typeNames = self.structure.treeFormats.typeNames() self.typeSubMenu.clear() usedShortcuts = [] for name in typeNames: shortcutPos = 0 try: while [shortcutPos] in usedShortcuts: shortcutPos += 1 usedShortcuts.append(name[shortcutPos]) text = '{0}&{1}'.format(name[:shortcutPos], name[shortcutPos:]) except IndexError: text = name action = self.typeSubMenu.addAction(text) action.setCheckable(True) if name in selectTypeNames: action.setChecked(True) def showTypeContextMenu(self): """Show a type set menu at the current tree view item. """ self.activeWindow.treeView.showTypeMenu(self.typeSubMenu) def dataCopyType(self): """Copy the configuration from another TreeLine file. """ filters = ';;'.join((globalref.fileFilters['trlnv3'], globalref.fileFilters['all'])) fileName, selectFilter = QFileDialog.getOpenFileName(self.activeWindow, _('TreeLine - Open Configuration File'), str(globalref.mainControl. defaultPathObj(True)), filters) if not fileName: return QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) newStructure = None try: with open(fileName, 'r', encoding='utf-8') as f: fileData = json.load(f) newStructure = treestructure.TreeStructure(fileData, addSpots=False) except IOError: pass except (ValueError, KeyError, TypeError): fileObj = open(fileName, 'rb') fileObj, encrypted = globalref.mainControl.decryptFile(fileObj) if not fileObj: QApplication.restoreOverrideCursor() return fileObj, compressed = globalref.mainControl.decompressFile(fileObj) if compressed or encrypted: try: textFileObj = io.TextIOWrapper(fileObj, encoding='utf-8') fileData = json.load(textFileObj) textFileObj.close() newStructure = treestructure.TreeStructure(fileData, addSpots=False) except (ValueError, KeyError, TypeError): pass fileObj.close() if not newStructure: QApplication.restoreOverrideCursor() QMessageBox.warning(self.activeWindow, 'TreeLine', _('Error - could not read file {0}'). format(fileName)) return undo.FormatUndo(self.structure.undoList, self.structure.treeFormats, treeformats.TreeFormats()) for nodeFormat in newStructure.treeFormats.values(): self.structure.treeFormats.addTypeIfMissing(nodeFormat) QApplication.restoreOverrideCursor() self.updateAll() globalref.mainControl.updateConfigDialog() def dataRegenRefs(self): """Force update of all conditional types & math fields. """ self.updateAll(False) def dataCloneMatches(self): """Convert all matching nodes into clones. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) selSpots = self.currentSelectionModel().selectedSpots() titleDict = {} for node in self.structure.nodeDict.values(): titleDict.setdefault(node.title(), set()).add(node) undoObj = undo.ChildListUndo(self.structure.undoList, self.structure.childList, addBranch=True) numChanges = 0 for node in self.structure.descendantGen(): matches = titleDict[node.title()] if len(matches) > 1: matches = matches.copy() matches.remove(node) for matchedNode in matches: if node.isIdentical(matchedNode): numChanges += 1 if len(matchedNode.spotRefs) > len(node.spotRefs): tmpNode = node node = matchedNode matchedNode = tmpNode numSpots = len(matchedNode.spotRefs) for parent in matchedNode.parents(): pos = parent.childList.index(matchedNode) parent.childList[pos] = node node.addSpotRef(parent) for child in matchedNode.descendantGen(): if len(child.spotRefs) <= numSpots: titleDict[child.title()].remove(child) self.structure.removeNodeDictRef(child) child.removeInvalidSpotRefs(False) if numChanges: msg = _('Converted {0} branches into clones').format(numChanges) self.currentSelectionModel().selectSpots([spot for spot in selSpots if spot.isValid()], False) self.updateAll() else: msg = _('No identical nodes found') self.structure.undoList.removeLastUndo(undoObj) QApplication.restoreOverrideCursor() QMessageBox.information(self.activeWindow, 'TreeLine', msg) def dataDetachClones(self): """Detach all cloned nodes in current branches. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) selSpots = self.currentSelectionModel().selectedBranchSpots() undoObj = undo.ChildListUndo(self.structure.undoList, [spot.parentSpot.nodeRef for spot in selSpots], addBranch=True) numChanges = 0 for branchSpot in selSpots: for spot in branchSpot.spotDescendantGen(): if (len(spot.nodeRef.spotRefs) > 1 and len(spot.parentSpot.nodeRef.spotRefs) <= 1): numChanges += 1 linkedNode = spot.nodeRef linkedNode.spotRefs.remove(spot) newNode = treenode.TreeNode(linkedNode.formatRef) newNode.data = linkedNode.data.copy() newNode.childList = linkedNode.childList[:] newNode.spotRefs.add(spot) spot.nodeRef = newNode parent = spot.parentSpot.nodeRef pos = parent.childList.index(linkedNode) parent.childList[pos] = newNode self.structure.addNodeDictRef(newNode) if numChanges: self.updateAll() else: self.structure.undoList.removeLastUndo(undoObj) QApplication.restoreOverrideCursor() def dataFlatCategory(self): """Collapse descendant nodes by merging fields. Overwrites data in any fields with the same name. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) selectList = self.currentSelectionModel().selectedBranches() undo.ChildDataUndo(self.structure.undoList, selectList, True, self.structure.treeFormats) origFormats = self.structure.undoList[-1].treeFormats for node in selectList: node.flatChildCategory(origFormats, self.structure) self.updateAll() globalref.mainControl.updateConfigDialog() QApplication.restoreOverrideCursor() def dataAddCategory(self): """Insert category nodes above children. """ selectList = self.currentSelectionModel().selectedBranches() children = [] for node in selectList: children.extend(node.childList) fieldList = self.structure.treeFormats.commonFields(children) if not fieldList: QMessageBox.warning(self.activeWindow, 'TreeLine', _('Cannot expand without common fields')) return dialog = miscdialogs.FieldSelectDialog(_('Category Fields'), _('Select fields for new level'), fieldList, self.activeWindow) if dialog.exec() != QDialog.DialogCode.Accepted: return QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) undo.ChildDataUndo(self.structure.undoList, selectList, True, self.structure.treeFormats) for node in selectList: node.addChildCategory(dialog.selectedFields, self.structure) self.updateAll() globalref.mainControl.updateConfigDialog() QApplication.restoreOverrideCursor() def dataSwapCategory(self): """Swap child and grandchild category nodes. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) selectList = self.currentSelectionModel().selectedBranches() undo.ChildListUndo(self.structure.undoList, selectList, addBranch=True) doneNodes = set() for ancestor in selectList: for child in ancestor.childList[:]: for catNode in child.childList[:]: if catNode not in doneNodes: doneNodes.add(catNode) childSpots = [spot.parentSpot for spot in catNode.spotRefs] childSpots.sort(key=operator.methodcaller('sortKey')) children = [childSpot.nodeRef for childSpot in childSpots] catNode.childList[0:0] = children for ancestor in selectList: position = 0 doneNodes = set() for child in ancestor.childList[:]: for catNode in child.childList[:]: if catNode not in doneNodes: doneNodes.add(catNode) for catSpot in catNode.spotRefs: child = catSpot.parentSpot.nodeRef child.childList = [] if child in ancestor.childList: position = ancestor.childList.index(child) del ancestor.childList[position] ancestor.childList.insert(position, catNode) position += 1 catNode.addSpotRef(ancestor) catNode.removeInvalidSpotRefs() self.updateAll() QApplication.restoreOverrideCursor() def toolsSpellCheck(self): """Spell check the tree text data. """ try: spellCheckOp = spellcheck.SpellCheckOperation(self) except spellcheck.SpellCheckError: return spellCheckOp.spellCheck() def findNodesByWords(self, wordList, titlesOnly=False, forward=True): """Search for and select nodes that match the word list criteria. Called from the text find dialog. Returns True if found, otherwise False. Arguments: wordList -- a list of words or phrases to find titleOnly -- search only in the title text if True forward -- next if True, previous if False """ currentSpot = self.currentSelectionModel().currentSpot() spot = currentSpot while True: if self.activeWindow.treeFilterView: spot = self.activeWindow.treeFilterView.nextPrevSpot(spot, forward) else: if forward: spot = spot.nextTreeSpot(True) else: spot = spot.prevTreeSpot(True) if spot is currentSpot: return False if spot.nodeRef.wordSearch(wordList, titlesOnly, spot): self.currentSelectionModel().selectSpots([spot], True, True) rightView = self.activeWindow.rightParentView() if not rightView: # view update required if (and only if) view is newly shown QApplication.processEvents() rightView = self.activeWindow.rightParentView() if rightView: rightView.highlightSearch(wordList=wordList) QApplication.processEvents() return True def findNodesByRegExp(self, regExpList, titlesOnly=False, forward=True): """Search for and select nodes that match the regular exp criteria. Called from the text find dialog. Returns True if found, otherwise False. Arguments: regExpList -- a list of regular expression objects titleOnly -- search only in the title text if True forward -- next if True, previous if False """ currentSpot = self.currentSelectionModel().currentSpot() spot = currentSpot while True: if self.activeWindow.treeFilterView: spot = self.activeWindow.treeFilterView.nextPrevSpot(spot, forward) else: if forward: spot = spot.nextTreeSpot(True) else: spot = spot.prevTreeSpot(True) if spot is currentSpot: return False if spot.nodeRef.regExpSearch(regExpList, titlesOnly, spot): self.currentSelectionModel().selectSpots([spot], True, True) rightView = self.activeWindow.rightParentView() if not rightView: # view update required if (and only if) view is newly shown QApplication.processEvents() rightView = self.activeWindow.rightParentView() if rightView: rightView.highlightSearch(regExpList=regExpList) return True def findNodesByCondition(self, conditional, forward=True): """Search for and select nodes that match the regular exp criteria. Called from the conditional find dialog. Returns True if found, otherwise False. Arguments: conditional -- the Conditional object to be evaluated forward -- next if True, previous if False """ currentSpot = self.currentSelectionModel().currentSpot() spot = currentSpot while True: if self.activeWindow.treeFilterView: spot = self.activeWindow.treeFilterView.nextPrevSpot(spot, forward) else: if forward: spot = spot.nextTreeSpot(True) else: spot = spot.prevTreeSpot(True) if spot is currentSpot: return False if conditional.evaluate(spot.nodeRef): self.currentSelectionModel().selectSpots([spot], True, True) return True def findNodesForReplace(self, searchText='', regExpObj=None, typeName='', fieldName='', forward=True): """Search for & select nodes that match the criteria prior to replace. Called from the find replace dialog. Returns True if found, otherwise False. Arguments: searchText -- the text to find if no regexp is given regExpObj -- the regular expression to find if given typeName -- if given, verify that this node matches this type fieldName -- if given, only find matches under this type name forward -- next if True, previous if False """ currentSpot = self.currentSelectionModel().currentSpot() lastFoundSpot, currentNumMatches = self.findReplaceSpotRef numMatches = currentNumMatches if lastFoundSpot is not currentSpot: numMatches = 0 spot = currentSpot if not forward: if numMatches == 0: numMatches = -1 # find last one if backward elif numMatches == 1: numMatches = sys.maxsize # no match if on first one else: numMatches -= 2 while True: matchedField, numMatches, fieldPos = (spot.nodeRef. searchReplace(searchText, regExpObj, numMatches, typeName, fieldName)) if matchedField: fieldNum = (spot.nodeRef.formatRef.fieldNames(). index(matchedField)) self.currentSelectionModel().selectSpots([spot], True, True) self.activeWindow.rightTabs.setCurrentWidget(self.activeWindow. editorSplitter) dataView = self.activeWindow.rightParentView() if not dataView: # view update required if (and only if) view is newly shown QApplication.processEvents() dataView = self.activeWindow.rightParentView() if dataView: dataView.highlightMatch(searchText, regExpObj, fieldNum, fieldPos - 1) self.findReplaceSpotRef = (spot, numMatches) return True if self.activeWindow.treeFilterView: node = self.activeWindow.treeFilterView.nextPrevSpot(spot, forward) else: if forward: spot = spot.nextTreeSpot(True) else: spot = spot.prevTreeSpot(True) if spot is currentSpot and currentNumMatches == 0: self.findReplaceSpotRef = (None, 0) return False numMatches = 0 if forward else -1 def replaceInCurrentNode(self, searchText='', regExpObj=None, typeName='', fieldName='', replaceText=None): """Replace the current match in the current node. Called from the find replace dialog. Returns True if replaced, otherwise False. Arguments: searchText -- the text to find if no regexp is given regExpObj -- the regular expression to find if given typeName -- if given, verify that this node matches this type fieldName -- if given, only find matches under this type name replaceText -- if not None, replace a match with this string """ spot = self.currentSelectionModel().currentSpot() lastFoundSpot, numMatches = self.findReplaceSpotRef if numMatches > 0: numMatches -= 1 if lastFoundSpot is not spot: numMatches = 0 dataUndo = undo.DataUndo(self.structure.undoList, spot.nodeRef) matchedField, num1, num2 = (spot.nodeRef. searchReplace(searchText, regExpObj, numMatches, typeName, fieldName, replaceText)) if ((searchText and searchText in replaceText) or (regExpObj and r'\g<0>' in replaceText) or (regExpObj and regExpObj.pattern.startswith('(') and regExpObj.pattern.endswith(')') and r'\1' in replaceText)): numMatches += 1 # check for recursive matches self.findReplaceSpotRef = (spot, numMatches) if matchedField: self.updateTreeNode(spot.nodeRef) self.updateRightViews() return True self.structure.undoList.removeLastUndo(dataUndo) return False def replaceAll(self, searchText='', regExpObj=None, typeName='', fieldName='', replaceText=None): """Replace all matches in all nodes. Called from the find replace dialog. Returns number of matches replaced. Arguments: searchText -- the text to find if no regexp is given regExpObj -- the regular expression to find if given typeName -- if given, verify that this node matches this type fieldName -- if given, only find matches under this type name replaceText -- if not None, replace a match with this string """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) dataUndo = undo.DataUndo(self.structure.undoList, self.structure.childList, addBranch=True) totalMatches = 0 for node in self.structure.nodeDict.values(): field, matchQty, num = node.searchReplace(searchText, regExpObj, 0, typeName, fieldName, replaceText, True) totalMatches += matchQty self.findReplaceSpotRef = (None, 0) if totalMatches > 0: self.updateAll(True) else: self.structure.undoList.removeLastUndo(dataUndo) QApplication.restoreOverrideCursor() return totalMatches def windowNew(self, checked=False, offset=30): """Open a new window for this file. Arguments: checked -- unused parameter needed by QAction signal offset -- location offset from previously saved position """ window = treewindow.TreeWindow(self.model, self.allActions) self.setWindowSignals(window) window.winMinimized.connect(globalref.mainControl.trayMinimize) self.windowList.append(window) self.updateWindowCaptions() oldControl = globalref.mainControl.activeControl if oldControl: try: oldControl.activeWindow.saveWindowGeom() except RuntimeError: # possibly avoid rare error of deleted c++ TreeWindow pass window.restoreWindowGeom(offset) self.activeWindow = window self.expandRootNodes() self.selectRootSpot() window.show() window.updateRightViews() TreeLine-3.2.1/source/treemaincontrol.py000066400000000000000000001423641506556630100203240ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treemaincontrol.py, provides a class for global tree commands # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import sys import pathlib import os.path import ast import io import gzip import zlib import datetime import platform from PyQt6.QtCore import QIODevice, QObject, Qt, PYQT_VERSION_STR, qVersion from PyQt6.QtGui import QAction, QColor, QFont, QPalette from PyQt6.QtNetwork import QLocalServer, QLocalSocket from PyQt6.QtWidgets import (QApplication, QDialog, QFileDialog, QMessageBox, QStyleFactory, QSystemTrayIcon) import globalref import treelocalcontrol import options import optiondefaults import recentfiles import p3 import icondict import imports import configdialog import miscdialogs import conditional import colorset import helpview try: from __main__ import __version__, __author__ except ImportError: __version__ = '' __author__ = '' try: from __main__ import docPath, iconPath, templatePath, samplePath except ImportError: docPath = None iconPath = None templatePath = None samplePath = None encryptPrefix = b'>>TL+enc' class TreeMainControl(QObject): """Class to handle all global controls. Provides methods for all controls and stores local control objects. """ def __init__(self, pathObjects, parent=None): """Initialize the main tree controls Arguments: pathObjects -- a list of file objects to open parent -- the parent QObject if given """ super().__init__(parent) self.localControls = [] self.activeControl = None self.trayIcon = None self.isTrayMinimized = False self.configDialog = None self.sortDialog = None self.numberingDialog = None self.findTextDialog = None self.findConditionDialog = None self.findReplaceDialog = None self.filterTextDialog = None self.filterConditionDialog = None self.basicHelpView = None self.passwords = {} self.creatingLocalControlFlag = False globalref.mainControl = self self.allActions = {} try: # check for existing TreeLine session socket = QLocalSocket() socket.connectToServer('treeline3-session', QIODevice.OpenModeFlag.WriteOnly) # if found, send files to open and exit TreeLine if socket.waitForConnected(1000): socket.write(bytes(repr([str(path) for path in pathObjects]), 'utf-8')) if socket.waitForBytesWritten(1000): socket.close() sys.exit(0) # start local server to listen for attempt to start new session self.serverSocket = QLocalServer() # remove any old servers still around after a crash in linux self.serverSocket.removeServer('treeline3-session') self.serverSocket.listen('treeline3-session') self.serverSocket.newConnection.connect(self.getSocket) except AttributeError: print(_('Warning: Could not create local socket')) mainVersion = '.'.join(__version__.split('.')[:2]) globalref.genOptions = options.Options('general', 'TreeLine', mainVersion, 'bellz') optiondefaults.setGenOptionDefaults(globalref.genOptions) globalref.miscOptions = options.Options('misc') optiondefaults.setMiscOptionDefaults(globalref.miscOptions) globalref.histOptions = options.Options('history') optiondefaults.setHistOptionDefaults(globalref.histOptions) globalref.toolbarOptions = options.Options('toolbar') optiondefaults.setToolbarOptionDefaults(globalref.toolbarOptions) globalref.keyboardOptions = options.Options('keyboard') optiondefaults.setKeyboardOptionDefaults(globalref.keyboardOptions) try: globalref.genOptions.readFile() globalref.miscOptions.readFile() globalref.histOptions.readFile() globalref.toolbarOptions.readFile() globalref.keyboardOptions.readFile() except IOError: errorDir = options.Options.basePath if not errorDir: errorDir = _('missing directory') QMessageBox.warning(None, 'TreeLine', _('Error - could not write config file to {}'). format(errorDir)) options.Options.basePath = None iconPathList = self.findResourcePaths('icons', iconPath) globalref.toolIcons = icondict.IconDict([path / 'toolbar' for path in iconPathList], ['', '32x32', '16x16']) globalref.toolIcons.loadAllIcons() windowIcon = globalref.toolIcons.getIcon('treelogo') if windowIcon: QApplication.setWindowIcon(windowIcon) globalref.treeIcons = icondict.IconDict(iconPathList, ['', 'tree']) icon = globalref.treeIcons.getIcon('default') QApplication.setStyle(QStyleFactory.create('Fusion')) self.colorSet = colorset.ColorSet() if globalref.miscOptions['ColorTheme'] != 'system': self.colorSet.setAppColors() self.recentFiles = recentfiles.RecentFileList() if globalref.genOptions['AutoFileOpen'] and not pathObjects: recentPath = self.recentFiles.firstPath() if recentPath: pathObjects = [recentPath] self.setupActions() self.systemFont = QApplication.font() self.updateAppFont() if globalref.genOptions['MinToSysTray']: self.createTrayIcon() QApplication.instance().focusChanged.connect(self.updateActionsAvail) if pathObjects: for pathObj in pathObjects: self.openFile(pathObj, True) else: self.createLocalControl() def getSocket(self): """Open a socket from an attempt to open a second Treeline instance. Opens the file (or raise and focus if open) in this instance. """ socket = self.serverSocket.nextPendingConnection() if socket and socket.waitForReadyRead(1000): data = str(socket.readAll(), 'utf-8') try: paths = ast.literal_eval(data) if paths: for path in paths: pathObj = pathlib.Path(path) if pathObj != self.activeControl.filePathObj: self.openFile(pathObj, True) else: self.activeControl.activeWindow.activateAndRaise() else: self.activeControl.activeWindow.activateAndRaise() except(SyntaxError, ValueError, TypeError, RuntimeError): pass def findResourcePaths(self, resourceName, preferredPath=''): """Return list of potential non-empty pathlib objects for the resource. List includes preferred, module and user option paths. Arguments: resourceName -- the typical name of the resource directory preferredPath -- add this as the second path if given """ # use abspath() - pathlib's resolve() can be buggy with network drives modPath = pathlib.Path(os.path.abspath(sys.path[0])) if modPath.is_file(): modPath = modPath.parent # for frozen binary pathList = [modPath / '..' / resourceName, modPath / resourceName] if options.Options.basePath: basePath = pathlib.Path(options.Options.basePath) pathList.insert(0, basePath / resourceName) if preferredPath: pathList.insert(1, pathlib.Path(preferredPath)) return [pathlib.Path(os.path.abspath(str(path))) for path in pathList if path.is_dir() and list(path.iterdir())] def findResourceFile(self, fileName, resourceName, preferredPath=''): """Return a path object for a resource file. Add a language code before the extension if it exists. Arguments: fileName -- the name of the file to find resourceName -- the typical name of the resource directory preferredPath -- search this path first if given """ fileList = [fileName] if globalref.lang and globalref.lang != 'C': fileList[0:0] = [fileName.replace('.', '_{0}.'. format(globalref.lang)), fileName.replace('.', '_{0}.'. format(globalref.lang[:2]))] for fileName in fileList: for path in self.findResourcePaths(resourceName, preferredPath): if (path / fileName).is_file(): return path / fileName return None def defaultPathObj(self, dirOnly=False): """Return a reasonable default file path object. Used for open, save-as, import and export. Arguments: dirOnly -- if True, do not include basename of file """ pathObj = None if self.activeControl: pathObj = self.activeControl.filePathObj if not pathObj: pathObj = self.recentFiles.firstDir() if not pathObj: pathObj = pathlib.Path.home() if dirOnly: pathObj = pathObj.parent return pathObj def openFile(self, pathObj, forceNewWindow=False, checkModified=False, importOnFail=True): """Open the file given by path if not already open. If already open in a different window, focus and raise the window. Arguments: pathObj -- the path object to read forceNewWindow -- if True, use a new window regardless of option checkModified -- if True & not new win, prompt if file modified importOnFail -- if True, prompts for import on non-TreeLine files """ match = [control for control in self.localControls if pathObj == control.filePathObj] if match and self.activeControl not in match: control = match[0] control.activeWindow.activateAndRaise() self.updateLocalControlRef(control) return if checkModified and not (forceNewWindow or globalref.genOptions['OpenNewWindow'] or self.activeControl.checkSaveChanges()): return if not self.checkAutoSave(pathObj): if not self.localControls: self.createLocalControl() return QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) try: fileModTime = datetime.datetime.fromtimestamp(pathObj.stat(). st_mtime) self.createLocalControl(pathObj, None, forceNewWindow, fileModTime) self.recentFiles.addItem(pathObj) if not (globalref.genOptions['SaveTreeStates'] and self.recentFiles.retrieveTreeState(self.activeControl)): self.activeControl.expandRootNodes() self.activeControl.selectRootSpot() QApplication.restoreOverrideCursor() except IOError: QApplication.restoreOverrideCursor() QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - could not read file {0}'). format(pathObj)) self.recentFiles.removeItem(pathObj) except (ValueError, KeyError, TypeError): fileObj = pathObj.open('rb') fileObj, encrypted = self.decryptFile(fileObj) if not fileObj: if not self.localControls: self.createLocalControl() QApplication.restoreOverrideCursor() return fileObj, compressed = self.decompressFile(fileObj) if compressed or encrypted: try: textFileObj = io.TextIOWrapper(fileObj, encoding='utf-8') self.createLocalControl(textFileObj, None, forceNewWindow, fileModTime) fileObj.close() textFileObj.close() self.recentFiles.addItem(pathObj) if not (globalref.genOptions['SaveTreeStates'] and self.recentFiles.retrieveTreeState(self. activeControl)): self.activeControl.expandRootNodes() self.activeControl.selectRootSpot() self.activeControl.compressed = compressed self.activeControl.encrypted = encrypted QApplication.restoreOverrideCursor() return except (ValueError, KeyError, TypeError): pass fileObj.close() importControl = imports.ImportControl(pathObj) structure = importControl.importOldTreeLine() if structure: self.createLocalControl(pathObj, structure, forceNewWindow) self.activeControl.printData.readData(importControl. treeLineRootAttrib) self.recentFiles.addItem(pathObj) self.activeControl.expandRootNodes() self.activeControl.imported = True QApplication.restoreOverrideCursor() return QApplication.restoreOverrideCursor() if importOnFail: importControl = imports.ImportControl(pathObj) structure = importControl.interactiveImport(True) if structure: self.createLocalControl(pathObj, structure, forceNewWindow) self.activeControl.imported = True return else: QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - invalid TreeLine file {0}'). format(pathObj)) self.recentFiles.removeItem(pathObj) if not self.localControls: self.createLocalControl() def decryptFile(self, fileObj): """Check for encryption and decrypt the fileObj if needed. Return a tuple of the file object and True if it was encrypted. Return None for the file object if the user cancels. Arguments: fileObj -- the file object to check and decrypt """ if fileObj.read(len(encryptPrefix)) != encryptPrefix: fileObj.seek(0) return (fileObj, False) fileContents = fileObj.read() fileName = fileObj.name fileObj.close() while True: pathObj = pathlib.Path(fileName) password = self.passwords.get(pathObj, '') if not password: QApplication.restoreOverrideCursor() dialog = miscdialogs.PasswordDialog(False, pathObj.name, QApplication. activeWindow()) if dialog.exec() != QDialog.DialogCode.Accepted: return (None, True) QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) password = dialog.password if miscdialogs.PasswordDialog.remember: self.passwords[pathObj] = password try: text = p3.p3_decrypt(fileContents, password.encode()) fileIO = io.BytesIO(text) fileIO.name = fileName return (fileIO, True) except p3.CryptError: try: del self.passwords[pathObj] except KeyError: pass def decompressFile(self, fileObj): """Check for compression and decompress the fileObj if needed. Return a tuple of the file object and True if it was compressed. Arguments: fileObj -- the file object to check and decompress """ prefix = fileObj.read(2) fileObj.seek(0) if prefix != b'\037\213': return (fileObj, False) try: newFileObj = gzip.GzipFile(fileobj=fileObj) except zlib.error: return (fileObj, False) newFileObj.name = fileObj.name return (newFileObj, True) def checkAutoSave(self, pathObj): """Check for presence of auto save file & prompt user. Return True if OK to contimue, False if aborting or already loaded. Arguments: pathObj -- the base path object to search for a backup """ if not globalref.genOptions['AutoSaveMinutes']: return True basePath = pathObj pathObj = pathlib.Path(str(pathObj) + '~') if not pathObj.is_file(): return True msgBox = QMessageBox(QMessageBox.Icon.Information, 'TreeLine', _('Backup file "{}" exists.\nA previous ' 'session may have crashed'). format(pathObj), QMessageBox.StandardButton.NoButton, QApplication.activeWindow()) restoreButton = msgBox.addButton(_('&Restore Backup'), QMessageBox.ButtonRole.ApplyRole) deleteButton = msgBox.addButton(_('&Delete Backup'), QMessageBox.ButtonRole.DestructiveRole) cancelButton = msgBox.addButton(_('&Cancel File Open'), QMessageBox.ButtonRole.RejectRole) msgBox.exec() if msgBox.clickedButton() == restoreButton: self.openFile(pathObj) if self.activeControl.filePathObj != pathObj: return False try: basePath.unlink() pathObj.rename(basePath) except OSError: QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - could not rename "{0}" to "{1}"'). format(pathObj, basePath)) return False self.activeControl.filePathObj = basePath self.activeControl.updateWindowCaptions() self.recentFiles.removeItem(pathObj) self.recentFiles.addItem(basePath) return False elif msgBox.clickedButton() == deleteButton: try: pathObj.unlink() except OSError: QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - could not remove backup file {}'). format(pathObj)) else: # cancel button return False return True def createLocalControl(self, pathObj=None, treeStruct=None, forceNewWindow=False, fileModTime=None): """Create a new local control object and add it to the list. Use an imported structure if given or open the file if path is given. Arguments: pathObj -- the path object or file object for the control to open treeStruct -- the imported structure to use forceNewWindow -- if True, use a new window regardless of option fileModTime -- file modified time for external modification checks """ self.creatingLocalControlFlag = True localControl = treelocalcontrol.TreeLocalControl(self.allActions, pathObj, treeStruct, fileModTime, forceNewWindow) localControl.controlActivated.connect(self.updateLocalControlRef) localControl.controlClosed.connect(self.removeLocalControlRef) self.localControls.append(localControl) self.updateLocalControlRef(localControl) self.creatingLocalControlFlag = False localControl.updateRightViews() localControl.updateCommandsAvail() def updateLocalControlRef(self, localControl): """Set the given local control as active. Called by signal from a window becoming active. Also updates non-modal dialogs. Arguments: localControl -- the new active local control """ if localControl != self.activeControl: self.activeControl = localControl if self.configDialog and self.configDialog.isVisible(): self.configDialog.setRefs(self.activeControl) def removeLocalControlRef(self, localControl): """Remove ref to local control based on a closing signal. Also do application exit clean ups if last control closing. Arguments: localControl -- the local control that is closing """ try: self.localControls.remove(localControl) except ValueError: return # skip for unreporducible bug - odd race condition? if globalref.genOptions['SaveTreeStates']: self.recentFiles.saveTreeState(localControl) if not self.localControls and not self.creatingLocalControlFlag: if globalref.genOptions['SaveWindowGeom']: localControl.windowList[0].saveWindowGeom() else: localControl.windowList[0].resetWindowGeom() self.recentFiles.writeItems() localControl.windowList[0].saveToolbarPosition() globalref.histOptions.writeFile() if self.trayIcon: self.trayIcon.hide() # stop listening for session connections try: self.serverSocket.close() del self.serverSocket except AttributeError: pass if self.localControls: # make sure a window is active (may not be focused), to avoid # bugs due to a deleted current window newControl = self.localControls[0] newControl.setActiveWin(newControl.windowList[0]) localControl.deleteLater() def createTrayIcon(self): """Create a new system tray icon if not already created. """ if QSystemTrayIcon.isSystemTrayAvailable(): if not self.trayIcon: self.trayIcon = QSystemTrayIcon(QApplication.windowIcon()) self.trayIcon.activated.connect(self.toggleTrayShow) self.trayIcon.show() def trayMinimize(self): """Minimize to tray based on window minimize signal. """ if self.trayIcon and QSystemTrayIcon.isSystemTrayAvailable(): # skip minimize to tray if not all windows minimized for control in self.localControls: for window in control.windowList: if not window.isMinimized(): return for control in self.localControls: for window in control.windowList: window.hide() self.isTrayMinimized = True def toggleTrayShow(self): """Toggle show and hide application based on system tray icon click. """ if self.isTrayMinimized: for control in self.localControls: for window in control.windowList: window.show() window.showNormal() self.activeControl.activeWindow.treeView.setFocus() else: for control in self.localControls: for window in control.windowList: window.hide() self.isTrayMinimized = not self.isTrayMinimized def updateConfigDialog(self): """Update the config dialog for changes if it exists. """ if self.configDialog: self.configDialog.reset() def currentStatusBar(self): """Return the status bar from the current main window. """ return self.activeControl.activeWindow.statusBar() def windowActions(self): """Return a list of window menu actions from each local control. """ actions = [] for control in self.localControls: actions.extend(control.windowActions(len(actions) + 1, control == self.activeControl)) return actions def updateActionsAvail(self, oldWidget, newWidget): """Update command availability based on focus changes. Arguments: oldWidget -- the previously focused widget newWidget -- the newly focused widget """ self.allActions['FormatSelectAll'].setEnabled(hasattr(newWidget, 'selectAll') and not hasattr(newWidget, 'editTriggers')) def setupActions(self): """Add the actions for contols at the global level. """ fileNewAct = QAction(_('&New...'), self, toolTip=_('New File'), statusTip=_('Start a new file')) fileNewAct.triggered.connect(self.fileNew) self.allActions['FileNew'] = fileNewAct fileOpenAct = QAction(_('&Open...'), self, toolTip=_('Open File'), statusTip=_('Open a file from disk')) fileOpenAct.triggered.connect(self.fileOpen) self.allActions['FileOpen'] = fileOpenAct fileSampleAct = QAction(_('Open Sa&mple...'), self, toolTip=_('Open Sample'), statusTip=_('Open a sample file')) fileSampleAct.triggered.connect(self.fileOpenSample) self.allActions['FileOpenSample'] = fileSampleAct fileImportAct = QAction(_('&Import...'), self, statusTip=_('Open a non-TreeLine file')) fileImportAct.triggered.connect(self.fileImport) self.allActions['FileImport'] = fileImportAct fileQuitAct = QAction(_('&Quit'), self, statusTip=_('Exit the application')) fileQuitAct.triggered.connect(self.fileQuit) self.allActions['FileQuit'] = fileQuitAct dataConfigAct = QAction(_('&Configure Data Types...'), self, statusTip=_('Modify data types, fields & output lines'), checkable=True) dataConfigAct.triggered.connect(self.dataConfigDialog) self.allActions['DataConfigType'] = dataConfigAct dataVisualConfigAct = QAction(_('Show C&onfiguration Structure...'), self, statusTip=_('Show read-only visualization of type structure')) dataVisualConfigAct.triggered.connect(self.dataVisualConfig) self.allActions['DataVisualConfig'] = dataVisualConfigAct dataSortAct = QAction(_('Sor&t Nodes...'), self, statusTip=_('Define node sort operations'), checkable=True) dataSortAct.triggered.connect(self.dataSortDialog) self.allActions['DataSortNodes'] = dataSortAct dataNumberingAct = QAction(_('Update &Numbering...'), self, statusTip=_('Update node numbering fields'), checkable=True) dataNumberingAct.triggered.connect(self.dataNumberingDialog) self.allActions['DataNumbering'] = dataNumberingAct toolsFindTextAct = QAction(_('&Find Text...'), self, statusTip=_('Find text in node titles & data'), checkable=True) toolsFindTextAct.triggered.connect(self.toolsFindTextDialog) self.allActions['ToolsFindText'] = toolsFindTextAct toolsFindConditionAct = QAction(_('&Conditional Find...'), self, statusTip=_('Use field conditions to find nodes'), checkable=True) toolsFindConditionAct.triggered.connect(self.toolsFindConditionDialog) self.allActions['ToolsFindCondition'] = toolsFindConditionAct toolsFindReplaceAct = QAction(_('Find and &Replace...'), self, statusTip=_('Replace text strings in node data'), checkable=True) toolsFindReplaceAct.triggered.connect(self.toolsFindReplaceDialog) self.allActions['ToolsFindReplace'] = toolsFindReplaceAct toolsFilterTextAct = QAction(_('&Text Filter...'), self, statusTip=_('Filter nodes to only show text matches'), checkable=True) toolsFilterTextAct.triggered.connect(self.toolsFilterTextDialog) self.allActions['ToolsFilterText'] = toolsFilterTextAct toolsFilterConditionAct = QAction(_('C&onditional Filter...'), self, statusTip=_('Use field conditions to filter nodes'), checkable=True) toolsFilterConditionAct.triggered.connect(self. toolsFilterConditionDialog) self.allActions['ToolsFilterCondition'] = toolsFilterConditionAct toolsGenOptionsAct = QAction(_('&General Options...'), self, statusTip=_('Set user preferences for all files')) toolsGenOptionsAct.triggered.connect(self.toolsGenOptions) self.allActions['ToolsGenOptions'] = toolsGenOptionsAct toolsShortcutAct = QAction(_('Set &Keyboard Shortcuts...'), self, statusTip=_('Customize keyboard commands')) toolsShortcutAct.triggered.connect(self.toolsCustomShortcuts) self.allActions['ToolsShortcuts'] = toolsShortcutAct toolsToolbarAct = QAction(_('C&ustomize Toolbars...'), self, statusTip=_('Customize toolbar buttons')) toolsToolbarAct.triggered.connect(self.toolsCustomToolbars) self.allActions['ToolsToolbars'] = toolsToolbarAct toolsFontsAct = QAction(_('Customize Fo&nts...'), self, statusTip=_('Customize fonts in various views')) toolsFontsAct.triggered.connect(self.toolsCustomFonts) self.allActions['ToolsFonts'] = toolsFontsAct toolsColorsAct = QAction(_('Custo&mize Colors...'), self, statusTip=_('Customize GUI colors and themes')) toolsColorsAct.triggered.connect(self.toolsCustomColors) self.allActions['ToolsColors'] = toolsColorsAct formatSelectAllAct = QAction(_('&Select All'), self, statusTip=_('Select all text in an editor')) formatSelectAllAct.setEnabled(False) formatSelectAllAct.triggered.connect(self.formatSelectAll) self.allActions['FormatSelectAll'] = formatSelectAllAct helpBasicAct = QAction(_('&Basic Usage...'), self, statusTip=_('Display basic usage instructions')) helpBasicAct.triggered.connect(self.helpViewBasic) self.allActions['HelpBasic'] = helpBasicAct helpFullAct = QAction(_('&Full Documentation...'), self, statusTip=_('Open a TreeLine file with full documentation')) helpFullAct.triggered.connect(self.helpViewFull) self.allActions['HelpFull'] = helpFullAct helpAboutAct = QAction(_('&About TreeLine...'), self, statusTip=_('Display version info about this program')) helpAboutAct.triggered.connect(self.helpAbout) self.allActions['HelpAbout'] = helpAboutAct for name, action in self.allActions.items(): icon = globalref.toolIcons.getIcon(name.lower()) if icon: action.setIcon(icon) key = globalref.keyboardOptions[name] if not key.isEmpty(): action.setShortcut(key) def fileNew(self): """Start a new blank file. """ if (globalref.genOptions['OpenNewWindow'] or self.activeControl.checkSaveChanges()): searchPaths = self.findResourcePaths('templates', templatePath) if searchPaths: dialog = miscdialogs.TemplateFileDialog(_('New File'), _('&Select Template'), searchPaths) if dialog.exec() == QDialog.DialogCode.Accepted: self.createLocalControl(dialog.selectedPath()) self.activeControl.filePathObj = None self.activeControl.updateWindowCaptions() self.activeControl.expandRootNodes() else: self.createLocalControl() self.activeControl.selectRootSpot() def fileOpen(self): """Prompt for a filename and open it. """ if (globalref.genOptions['OpenNewWindow'] or self.activeControl.checkSaveChanges()): filters = ';;'.join((globalref.fileFilters['trlnopen'], globalref.fileFilters['all'])) fileName, selFilter = QFileDialog.getOpenFileName(QApplication. activeWindow(), _('TreeLine - Open File'), str(self.defaultPathObj(True)), filters) if fileName: self.openFile(pathlib.Path(fileName)) def fileOpenSample(self): """Open a sample file from the doc directories. """ if (globalref.genOptions['OpenNewWindow'] or self.activeControl.checkSaveChanges()): searchPaths = self.findResourcePaths('samples', samplePath) dialog = miscdialogs.TemplateFileDialog(_('Open Sample File'), _('&Select Sample'), searchPaths, False) if dialog.exec() == QDialog.DialogCode.Accepted: self.createLocalControl(dialog.selectedPath()) name = dialog.selectedName() + '.trln' self.activeControl.filePathObj = pathlib.Path(name) self.activeControl.updateWindowCaptions() self.activeControl.expandRootNodes() self.activeControl.imported = True def fileImport(self): """Prompt for an import type, then a file to import. """ importControl = imports.ImportControl() structure = importControl.interactiveImport() if structure: self.createLocalControl(importControl.pathObj, structure) if importControl.treeLineRootAttrib: self.activeControl.printData.readData(importControl. treeLineRootAttrib) self.activeControl.imported = True def fileQuit(self): """Close all windows to exit the applications. """ for control in self.localControls[:]: control.closeWindows() def dataConfigDialog(self, show): """Show or hide the non-modal data config dialog. Arguments: show -- true if dialog should be shown, false to hide it """ if show: if not self.configDialog: self.configDialog = configdialog.ConfigDialog() dataConfigAct = self.allActions['DataConfigType'] self.configDialog.dialogShown.connect(dataConfigAct.setChecked) self.configDialog.setRefs(self.activeControl, True) self.configDialog.show() else: self.configDialog.close() def dataVisualConfig(self): """Show a TreeLine file to visualize the config structure. """ structure = (self.activeControl.structure.treeFormats. visualConfigStructure(str(self.activeControl. filePathObj))) self.createLocalControl(treeStruct=structure, forceNewWindow=True) self.activeControl.filePathObj = pathlib.Path('structure.trln') self.activeControl.updateWindowCaptions() self.activeControl.expandRootNodes() self.activeControl.imported = True win = self.activeControl.activeWindow win.rightTabs.setCurrentWidget(win.outputSplitter) def dataSortDialog(self, show): """Show or hide the non-modal data sort nodes dialog. Arguments: show -- true if dialog should be shown, false to hide it """ if show: if not self.sortDialog: self.sortDialog = miscdialogs.SortDialog() dataSortAct = self.allActions['DataSortNodes'] self.sortDialog.dialogShown.connect(dataSortAct.setChecked) self.sortDialog.show() else: self.sortDialog.close() def dataNumberingDialog(self, show): """Show or hide the non-modal update node numbering dialog. Arguments: show -- true if dialog should be shown, false to hide it """ if show: if not self.numberingDialog: self.numberingDialog = miscdialogs.NumberingDialog() dataNumberingAct = self.allActions['DataNumbering'] self.numberingDialog.dialogShown.connect(dataNumberingAct. setChecked) self.numberingDialog.show() if not self.numberingDialog.checkForNumberingFields(): self.numberingDialog.close() else: self.numberingDialog.close() def toolsFindTextDialog(self, show): """Show or hide the non-modal find text dialog. Arguments: show -- true if dialog should be shown """ if show: if not self.findTextDialog: self.findTextDialog = miscdialogs.FindFilterDialog() toolsFindTextAct = self.allActions['ToolsFindText'] self.findTextDialog.dialogShown.connect(toolsFindTextAct. setChecked) self.findTextDialog.selectAllText() self.findTextDialog.show() else: self.findTextDialog.close() def toolsFindConditionDialog(self, show): """Show or hide the non-modal conditional find dialog. Arguments: show -- true if dialog should be shown """ if show: if not self.findConditionDialog: dialogType = conditional.FindDialogType.findDialog self.findConditionDialog = (conditional. ConditionDialog(dialogType, _('Conditional Find'))) toolsFindConditionAct = self.allActions['ToolsFindCondition'] (self.findConditionDialog.dialogShown. connect(toolsFindConditionAct.setChecked)) else: self.findConditionDialog.loadTypeNames() self.findConditionDialog.show() else: self.findConditionDialog.close() def toolsFindReplaceDialog(self, show): """Show or hide the non-modal find and replace text dialog. Arguments: show -- true if dialog should be shown """ if show: if not self.findReplaceDialog: self.findReplaceDialog = miscdialogs.FindReplaceDialog() toolsFindReplaceAct = self.allActions['ToolsFindReplace'] self.findReplaceDialog.dialogShown.connect(toolsFindReplaceAct. setChecked) else: self.findReplaceDialog.loadTypeNames() self.findReplaceDialog.show() else: self.findReplaceDialog.close() def toolsFilterTextDialog(self, show): """Show or hide the non-modal filter text dialog. Arguments: show -- true if dialog should be shown """ if show: if not self.filterTextDialog: self.filterTextDialog = miscdialogs.FindFilterDialog(True) toolsFilterTextAct = self.allActions['ToolsFilterText'] self.filterTextDialog.dialogShown.connect(toolsFilterTextAct. setChecked) self.filterTextDialog.selectAllText() self.filterTextDialog.show() else: self.filterTextDialog.close() def toolsFilterConditionDialog(self, show): """Show or hide the non-modal conditional filter dialog. Arguments: show -- true if dialog should be shown """ if show: if not self.filterConditionDialog: dialogType = conditional.FindDialogType.filterDialog self.filterConditionDialog = (conditional. ConditionDialog(dialogType, _('Conditional Filter'))) toolsFilterConditionAct = (self. allActions['ToolsFilterCondition']) (self.filterConditionDialog.dialogShown. connect(toolsFilterConditionAct.setChecked)) else: self.filterConditionDialog.loadTypeNames() self.filterConditionDialog.show() else: self.filterConditionDialog.close() def toolsGenOptions(self): """Set general user preferences for all files. """ oldAutoSaveMinutes = globalref.genOptions['AutoSaveMinutes'] dialog = options.OptionDialog(globalref.genOptions, QApplication.activeWindow()) dialog.setWindowTitle(_('General Options')) if (dialog.exec() == QDialog.DialogCode.Accepted and globalref.genOptions.modified): globalref.genOptions.writeFile() self.recentFiles.updateOptions() if globalref.genOptions['MinToSysTray']: self.createTrayIcon() elif self.trayIcon: self.trayIcon.hide() autoSaveMinutes = globalref.genOptions['AutoSaveMinutes'] for control in self.localControls: for window in control.windowList: window.updateWinGenOptions() control.structure.undoList.setNumLevels() control.updateAll(False) if autoSaveMinutes != oldAutoSaveMinutes: control.resetAutoSave() def toolsCustomShortcuts(self): """Show dialog to customize keyboard commands. """ actions = self.activeControl.activeWindow.allActions dialog = miscdialogs.CustomShortcutsDialog(actions, QApplication. activeWindow()) dialog.exec() def toolsCustomToolbars(self): """Show dialog to customize toolbar buttons. """ actions = self.activeControl.activeWindow.allActions dialog = miscdialogs.CustomToolbarDialog(actions, self.updateToolbars, QApplication. activeWindow()) dialog.exec() def updateToolbars(self): """Update toolbars after changes in custom toolbar dialog. """ for control in self.localControls: for window in control.windowList: window.setupToolbars() def toolsCustomFonts(self): """Show dialog to customize fonts in various views. """ dialog = miscdialogs.CustomFontDialog(QApplication. activeWindow()) dialog.updateRequired.connect(self.updateCustomFonts) dialog.exec() def toolsCustomColors(self): """Show dialog to customize GUI colors ans themes. """ self.colorSet.showDialog(QApplication.activeWindow()) def updateCustomFonts(self): """Update fonts in all windows based on a dialog signal. """ self.updateAppFont() for control in self.localControls: for window in control.windowList: window.updateFonts() control.printData.setDefaultFont() for control in self.localControls: control.updateAll(False) def updateAppFont(self): """Update application default font from settings. """ appFont = QFont(self.systemFont) appFontName = globalref.miscOptions['AppFont'] if appFontName: appFont.fromString(appFontName) QApplication.setFont(appFont) def formatSelectAll(self): """Select all text in any currently focused editor. """ try: QApplication.focusWidget().selectAll() except AttributeError: pass def helpViewBasic(self): """Display basic usage instructions. """ if not self.basicHelpView: path = self.findResourceFile('basichelp.html', 'doc', docPath) if not path: QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - basic help file not found')) return self.basicHelpView = helpview.HelpView(path, _('TreeLine Basic Usage'), globalref.toolIcons) self.basicHelpView.show() def helpViewFull(self): """Open a TreeLine file with full documentation. """ path = self.findResourceFile('documentation.trln', 'doc', docPath) if not path: QMessageBox.warning(QApplication.activeWindow(), 'TreeLine', _('Error - documentation file not found')) return self.createLocalControl(path, forceNewWindow=True) self.activeControl.filePathObj = pathlib.Path('documentation.trln') self.activeControl.updateWindowCaptions() self.activeControl.expandRootNodes() self.activeControl.imported = True win = self.activeControl.activeWindow win.rightTabs.setCurrentWidget(win.outputSplitter) def helpAbout(self): """ Display version info about this program. """ pyVersion = '.'.join([repr(num) for num in sys.version_info[:3]]) textLines = [_('TreeLine version {0}').format(__version__), _('written by {0}').format(__author__), '', _('Library versions:'), ' Python: {0}'.format(pyVersion), ' Qt: {0}'.format(qVersion()), ' PyQt: {0}'.format(PYQT_VERSION_STR), ' OS: {0}'.format(platform.platform())] dialog = miscdialogs.AboutDialog('TreeLine', textLines, QApplication.windowIcon(), QApplication.activeWindow()) dialog.exec() def setThemeColors(): """Set the app colors based on options setting. """ if globalref.genOptions['ColorTheme'] == optiondefaults.colorThemes[1]: # dark theme myDarkGray = QColor(53, 53, 53) myVeryDarkGray = QColor(25, 25, 25) myBlue = QColor(42, 130, 218) palette = QPalette() palette.setColor(QPalette.ColorRole.Window, myDarkGray) palette.setColor(QPalette.ColorRole.WindowText, Qt.GlobalColor.white) palette.setColor(QPalette.ColorRole.Base, myVeryDarkGray) palette.setColor(QPalette.ColorRole.AlternateBase, myDarkGray) palette.setColor(QPalette.ColorRole.ToolTipBase, Qt.GlobalColor.darkBlue) palette.setColor(QPalette.ColorRole.ToolTipText, Qt.GlobalColor.lightGray) palette.setColor(QPalette.ColorRole.Text, Qt.GlobalColor.white) palette.setColor(QPalette.ColorRole.Button, myDarkGray) palette.setColor(QPalette.ColorRole.ButtonText, Qt.GlobalColor.white) palette.setColor(QPalette.ColorRole.BrightText, Qt.GlobalColor.red) palette.setColor(QPalette.ColorRole.Link, myBlue) palette.setColor(QPalette.ColorRole.Highlight, myBlue) palette.setColor(QPalette.ColorRole.HighlightedText, Qt.GlobalColor.black) palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, Qt.GlobalColor.darkGray) palette.setColor(QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, Qt.GlobalColor.darkGray) QApplication.setPalette(palette) TreeLine-3.2.1/source/treemodel.py000066400000000000000000000212621506556630100170700ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treemodel.py, provides a class for the tree's data # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import json from PyQt6.QtCore import (QAbstractItemModel, QMimeData, QModelIndex, Qt, pyqtSignal) import undo import treestructure import globalref class TreeModel(QAbstractItemModel): """Class interfacing between the tree structure and the tree view. """ # first arg is set file modified, second is update trees in other views treeModified = pyqtSignal(bool, bool) def __init__(self, treeStructure, parent=None): """Initialize a TreeModel. Arguments: treeStructure -- a ref to the main tree structure parent -- optional QObject parent for the model """ super().__init__(parent) self.treeStructure = treeStructure def index(self, row, column, parentIndex): """Returns the index of a spot in the model based on the parent index. Uses createIndex() to generate the model indices. Arguments: row -- the row of the model node column -- the column (always 0 for now) parentIndex -- the parent's model index in the tree structure """ try: if not parentIndex.isValid(): node = self.treeStructure.childList[row] fakeSpot = list(self.treeStructure.spotRefs)[0] spot = node.matchedSpot(fakeSpot) return self.createIndex(row, column, spot) parentSpot = parentIndex.internalPointer() node = parentSpot.nodeRef.childList[row] return self.createIndex(row, column, node.matchedSpot(parentSpot)) except IndexError: return QModelIndex() def parent(self, index): """Returns the parent model index of the spot at the given index. Arguments: index -- the child model index """ try: parentSpot = index.internalPointer().parentSpot if parentSpot.parentSpot: return self.createIndex(parentSpot.row(), 0, parentSpot) except AttributeError: # attempt to fix an unreproducable bug deleting deep nodes pass return QModelIndex() def rowCount(self, parentIndex): """Returns the number of children for the spot at the given index. Arguments: parentIndex -- the parent model index """ try: parentSpot = parentIndex.internalPointer() return parentSpot.nodeRef.numChildren() except AttributeError: # top level if no parentIndex return len(self.treeStructure.childList) def columnCount(self, parentIndex): """The number of columns -- always 1 for now. """ return 1 def data(self, index, role=Qt.ItemDataRole.DisplayRole): """Return the output data for the node in the given role. Arguments: index -- the spot's model index role -- the type of data requested """ spot = index.internalPointer() if not spot: return None node = spot.nodeRef if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): return node.title() if (role == Qt.ItemDataRole.DecorationRole and globalref.genOptions['ShowTreeIcons']): return globalref.treeIcons.getIcon(node.formatRef.iconName, True) return None def setData(self, index, value, role=Qt.ItemDataRole.EditRole): """Set node title after edit operation. Return True on success. Arguments: index -- the node's model index value -- the string result of the editing role -- the edit role of the data """ if role != Qt.ItemDataRole.EditRole: return super().setData(index, value, role) node = index.internalPointer().nodeRef dataUndo = undo.DataUndo(self.treeStructure.undoList, node) if node.setTitle(value): self.dataChanged.emit(index, index) self.treeModified.emit(True, False) return True self.treeStructure.undoList.removeLastUndo(dataUndo) return False def flags(self, index): """Return the flags for the node at the given index. Arguments: index -- the node's model index """ return (Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsDragEnabled | Qt.ItemFlag.ItemIsDropEnabled) def mimeData(self, indexList): """Return a mime data object for the given node index branches. Arguments: indexList -- a list of node indexes to convert """ spots = [index.internalPointer() for index in indexList] # remove selections from the same branch TreeModel.storedDragSpots = [spot for spot in spots if spot.parentSpotSet(). isdisjoint(set(spots))] nodes = [spot.nodeRef for spot in TreeModel.storedDragSpots] TreeModel.storedDragModel = self struct = treestructure.TreeStructure(topNodes=nodes, addSpots=False) generics = {formatRef.genericType for formatRef in struct.treeFormats.values() if formatRef.genericType} for generic in generics: genericRef = self.treeStructure.treeFormats[generic] struct.treeFormats.addTypeIfMissing(genericRef) for formatRef in genericRef.derivedTypes: struct.treeFormats.addTypeIfMissing(formatRef) data = struct.fileData() dataStr = json.dumps(data, indent=0, sort_keys=True) mime = QMimeData() mime.setData('application/json', bytes(dataStr, encoding='utf-8')) return mime def mimeTypes(self): """Return a list of supported mime types for model objects. """ return ['application/json'] def supportedDropActions(self): """Return drop action enum values that are supported by this model. """ return Qt.DropAction.CopyAction | Qt.DropAction.MoveAction def dropMimeData(self, mimeData, dropAction, row, column, index): """Decode mime data and add as a child node to the given index. Return True if successful. Arguments: mimeData -- data for the node branch to be added dropAction -- a drop type enum value row -- a row number for the drop location column -- the column number for the drop location (normally 0) index -- the index of the parent node for the drop """ parent = (index.internalPointer().nodeRef if index.internalPointer() else self.treeStructure) isMove = (dropAction == Qt.DropAction.MoveAction and TreeModel.storedDragModel == self) undoParents = [parent] if isMove: moveParents = {spot.parentSpot.nodeRef for spot in TreeModel.storedDragSpots} undoParents.extend(list(moveParents)) newStruct = treestructure.structFromMimeData(mimeData) # check for valid structure and no circular clone ref and not siblings: if newStruct and (not isMove or (not parent.uId in newStruct.nodeDict and (row >= 0 or {node.uId for node in parent.childList}. isdisjoint({node.uId for node in newStruct.childList})))): undo.ChildListUndo(self.treeStructure.undoList, undoParents, treeFormats=self.treeStructure.treeFormats) if isMove: for spot in TreeModel.storedDragSpots: self.treeStructure.deleteNodeSpot(spot) newStruct.replaceClonedBranches(self.treeStructure) else: newStruct.replaceDuplicateIds(self.treeStructure.nodeDict) self.treeStructure.addNodesFromStruct(newStruct, parent, row) return True return False TreeLine-3.2.1/source/treenode.py000066400000000000000000000770161506556630100167250ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treenode.py, provides a class to store tree node data # # TreeLine, an information storage program # Copyright (C) 2020, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import uuid import operator import itertools import treespot import nodeformat _replaceBackrefRe = (re.compile(r'\\(\d+)'), re.compile(r'\\g<(\d+)>')) _origBackrefMatch = None class TreeNode: """Class to store tree node data and the tree's linked structure. Stores a data dict, lists of children and a format name string. Provides methods to get info on the structure and the data. """ def __init__(self, formatRef, fileData=None): """Initialize a tree node. Arguments: formatRef -- a ref to this node's format info fileData -- a dict with uid, data, child refs & parent refs """ self.formatRef = formatRef if not fileData: fileData = {} self.uId = fileData.get('uid', uuid.uuid1().hex) self.data = fileData.get('data', {}) self.tmpChildRefs = fileData.get('children', []) self.childList = [] self.spotRefs = set() def assignRefs(self, nodeDict): """Add actual refs to child nodes from data in self.tmpChildRefs. Any bad node refs (corrupt file data) are left in self.tmpChildRefs. Arguments: nodeDict -- all nodes stored by uid """ try: self.childList = [nodeDict[uid] for uid in self.tmpChildRefs] self.tmpChildRefs = [] except KeyError: # due to corrupt file data badChildRefs = [] for uid in self.tmpChildRefs: if uid in nodeDict: self.childList.append(nodeDict[uid]) else: badChildRefs.append(uid) self.tmpChildRefs = badChildRefs def generateSpots(self, parentSpot): """Recursively generate spot references for this branch. Arguments: parentSpot -- the parent spot reference """ spot = treespot.TreeSpot(self, parentSpot) self.spotRefs.add(spot) for child in self.childList: child.generateSpots(spot) def addSpotRef(self, parentNode, includeChildren=True): """Add a spot ref here to the given parent if not already there. If changed, propogate to descendant nodes. Arguments: parentNode -- the parent to ref in the new spot includeChildren -- if True, propogate to descendant nodes """ changed = False origParentSpots = {spot.parentSpot for spot in self.spotRefs} for parentSpot in parentNode.spotRefs: if parentSpot not in origParentSpots: self.spotRefs.add(treespot.TreeSpot(self, parentSpot)) changed = True if changed and includeChildren: for child in self.childList: child.addSpotRef(self) def removeInvalidSpotRefs(self, includeChildren=True, forceDesend=False): """Verify existing spot refs and remove any that aren't valid. If changed and includeChilderen, propogate to descendant nodes. Arguments: includeChildren -- if True, propogate to descendants if changes forceDesend -- if True, force propogate to descendant nodes """ goodSpotRefs = {spot for spot in self.spotRefs if (self in spot.parentSpot.nodeRef.childList and spot.parentSpot in spot.parentSpot.nodeRef.spotRefs)} changed = len(self.spotRefs) != len(goodSpotRefs) self.spotRefs = goodSpotRefs if includeChildren and (changed or forceDesend): for child in self.childList: child.removeInvalidSpotRefs(includeChildren) def spotByNumber(self, num): """Return the spot at the given rank in the spot sequence. Arguments: num -- the rank number to return """ spotList = sorted(list(self.spotRefs), key=operator.methodcaller('sortKey')) return spotList[num] def matchedSpot(self, parentSpot): """Return the spot for this node that matches a parent spot. Return None if not found. Arguments: parentSpot -- the parent to match """ for spot in self.spotRefs: if spot.parentSpot is parentSpot: return spot return None def setInitDefaultData(self, overwrite=False): """Add initial default data from fields into internal data. Arguments: overwrite -- if true, replace previous data entries """ self.formatRef.setInitDefaultData(self.data, overwrite) def parents(self): """Return a set of parent nodes for this node. Returns an empty set if called from the tree structure. """ try: return {spot.parentSpot.nodeRef for spot in self.spotRefs} except AttributeError: return set() def numChildren(self): """Return number of children. """ return len(self.childList) def descendantGen(self): """Return a generator to step through all nodes in this branch. Includes self and closed nodes. """ yield self for child in self.childList: for node in child.descendantGen(): yield node def ancestors(self): """Return a set of all ancestor nodes (including self). """ spots = set() for spot in self.spotRefs: spots.update(spot.spotChain()) return {spot.nodeRef for spot in spots} def treeStructureRef(self): """Return the tree structure based on the root spot ref. """ return next(iter(self.spotRefs)).rootSpot().nodeRef def fileData(self): """Return the file data dict for this node. """ children = [node.uId for node in self.childList] fileData = {'format': self.formatRef.name, 'uid': self.uId, 'data': self.data, 'children': children} return fileData def title(self, spotRef=None): """Return the title string for this node. If spotRef not given, ancestor fields assume first spot. Arguments: spotRef -- optional, used for ancestor field refs """ return self.formatRef.formatTitle(self, spotRef) def setTitle(self, title): """Change this node's data based on a new title string. Return True if successfully changed. """ if title == self.title(): return False return self.formatRef.extractTitleData(title, self.data) def output(self, plainText=False, keepBlanks=False, spotRef=None): """Return a list of formatted text output lines. If spotRef not given, ancestor fields assume first spot. Arguments: plainText -- if True, remove HTML markup from fields and formats keepBlanks -- if True, keep lines with empty fields spotRef -- optional, used for ancestor field refs """ return self.formatRef.formatOutput(self, plainText, keepBlanks, spotRef) def changeDataType(self, formatRef): """Change this node's data type to the given name. Set init default data and update the title if blank. Arguments: formatRef -- the new tree format type """ origTitle = self.title() self.formatRef = formatRef formatRef.setInitDefaultData(self.data) if not formatRef.formatTitle(self): formatRef.extractTitleData(origTitle, self.data) def setConditionalType(self, treeStructure): """Set self to type based on auto conditional settings. Return True if type is changed. Arguments: treeStructure -- a ref to the tree structure """ if self.formatRef not in treeStructure.treeFormats.conditionalTypes: return False if self.formatRef.genericType: genericFormat = treeStructure.treeFormats[self.formatRef. genericType] else: genericFormat = self.formatRef formatList = [genericFormat] + genericFormat.derivedTypes formatList.remove(self.formatRef) formatList.insert(0, self.formatRef) # reorder to give priority neutralResult = None newType = None for typeFormat in formatList: if typeFormat.conditional: if typeFormat.conditional.evaluate(self): newType = typeFormat break elif not neutralResult: neutralResult = typeFormat if not newType and neutralResult: newType = neutralResult if newType and newType is not self.formatRef: self.changeDataType(newType) return True return False def setDescendantConditionalTypes(self, treeStructure): """Set auto conditional types for self and all descendants. Return number of changes made. Arguments: treeStructure -- a ref to the tree structure """ if not treeStructure.treeFormats.conditionalTypes: return 0 changes = 0 for node in self.descendantGen(): if node.setConditionalType(treeStructure): changes += 1 return changes def setData(self, field, editorText): """Set the data entry for the given field to editorText. If the data does not match the format, sets to the raw text and raises a ValueError. Arguments: field-- the field object to be set editorText -- new text data from an editor """ try: self.data[field.name] = field.storedText(editorText) except ValueError as err: if len(err.args) >= 2: self.data[field.name] = err.args[1] else: self.data[field.name] = editorText raise ValueError def wordSearch(self, wordList, titleOnly=False, spotRef=None): """Return True if all words in wordlist are found in this node's data. Arguments: wordList -- a list of words or phrases to find titleOnly -- search only in the title text if True spotRef -- an optional spot reference for ancestor field refs """ dataStr = self.title(spotRef).lower() if not titleOnly: # join with null char so phrase matches don't cross borders dataStr = '{0}\0{1}'.format(dataStr, '\0'.join(self.data.values()).lower()) for word in wordList: if word not in dataStr: return False return True def regExpSearch(self, regExpList, titleOnly=False, spotRef=None): """Return True if the regular expression is found in this node's data. Arguments: regExpList -- a list of regular expression objects to find titleOnly -- search only in the title text if True spotRef -- an optional spot reference for ancestor field refs """ dataStr = self.title(spotRef) if not titleOnly: # join with null char so phrase matches don't cross borders dataStr = '{0}\0{1}'.format(dataStr, '\0'.join(self.data.values())) for regExpObj in regExpList: if not regExpObj.search(dataStr): return False return True def searchReplace(self, searchText='', regExpObj=None, skipMatches=0, typeName='', fieldName='', replaceText=None, replaceAll=False): """Find the search text in the field data and optionally replace it. Returns a tuple of the fieldName where found (empty string if not found), the node match number and the field match number. Returns the last match if skipMatches < 0 (not used with replace). Arguments: searchText -- the text to find if regExpObj is None regExpObj -- the regular expression to find if not None skipMatches -- number of already found matches to skip in this node typeName -- if given, verify that this node matches this type fieldName -- if given, only find matches under this type name replaceText -- if not None, replace a match with this string replaceAll -- if True, replace all matches (returns last fieldName) """ if typeName and typeName != self.formatRef.name: return ('', 0, 0) try: fields = ([self.formatRef.fieldDict[fieldName]] if fieldName else self.formatRef.fields()) except KeyError: return ('', 0, 0) # field not in this type matchedFieldname = '' findCount = 0 prevFieldFindCount = 0 for field in fields: try: fieldText = field.editorText(self) except ValueError: fieldText = self.data.get(field.name, '') fieldFindCount = 0 pos = 0 while True: if pos >= len(fieldText) and pos > 0: break if regExpObj: match = regExpObj.search(fieldText, pos) pos = match.start() if match else -1 else: pos = fieldText.lower().find(searchText, pos) if not searchText and fieldText: pos = -1 # skip invalid find of empty string if pos < 0: break findCount += 1 fieldFindCount += 1 prevFieldFindCount = fieldFindCount matchLen = (len(match.group()) if regExpObj else len(searchText)) if findCount > skipMatches: matchedFieldname = field.name if replaceText is not None: replace = replaceText if regExpObj: global _origBackrefMatch _origBackrefMatch = match for backrefRe in _replaceBackrefRe: replace = backrefRe.sub(self.replaceBackref, replace) fieldText = (fieldText[:pos] + replace + fieldText[pos + matchLen:]) try: self.setData(field, fieldText) except ValueError: pass if not replaceAll and skipMatches >= 0: return (field.name, findCount, fieldFindCount) pos = pos + matchLen if matchLen else pos + 1 if not matchedFieldname: findCount = prevFieldFindCount = 0 return (matchedFieldname, findCount, prevFieldFindCount) @staticmethod def replaceBackref(match): """Return the re match group from _origBackrefMatch for replacement. Used for reg exp backreference replacement. Arguments: match -- the backref match in the replacement string """ return _origBackrefMatch.group(int(match.group(1))) def addNewChild(self, treeStructure, posRefNode=None, insertBefore=True, newTitle=_('New')): """Add a new child node with this node as the parent. Insert the new node near the posRefNode or at the end if no ref node. Return the new node. Arguments: treeStructure -- a ref to the tree structure posRefNode -- a child reference for the new node's position insertBefore -- insert before the ref node if True, after if False """ try: newFormat = treeStructure.treeFormats[self.formatRef.childType] except (KeyError, AttributeError): if posRefNode: newFormat = posRefNode.formatRef elif self.childList: newFormat = self.childList[0].formatRef else: newFormat = self.formatRef newNode = TreeNode(newFormat) pos = len(self.childList) if posRefNode: pos = self.childList.index(posRefNode) if not insertBefore: pos += 1 self.childList.insert(pos, newNode) newNode.setInitDefaultData() newNode.addSpotRef(self) if newTitle and not newNode.title(): newNode.setTitle(newTitle) treeStructure.addNodeDictRef(newNode) return newNode def changeParent(self, oldParentSpot, newParentSpot, newPos=-1): """Move this node from oldParent to newParent. Used for indent and unindent commands. Arguments: oldParent -- the original parent spot newParent -- the new parent spot newPos -- the position in the new childList, -1 for append """ oldParent = oldParentSpot.nodeRef oldParent.childList.remove(self) newParent = newParentSpot.nodeRef if newPos >= 0: newParent.childList.insert(newPos, self) else: newParent.childList.append(self) # preserve one spot to maintain tree expand state self.matchedSpot(oldParentSpot).parentSpot = newParentSpot self.removeInvalidSpotRefs() self.addSpotRef(newParent) def replaceChildren(self, titleList, treeStructure): """Replace child nodes with titles from a text list. Nodes with matches in the titleList are kept, others are added or deleted as required. Arguments: titleList -- the list of new child titles treeStructure -- a ref to the tree structure """ try: newFormat = treeStructure.treeFormats[self.formatRef.childType] except (KeyError, AttributeError): newFormat = (self.childList[0].formatRef if self.childList else self.formatRef) matchList = [] remainTitles = [child.title() for child in self.childList] for title in titleList: try: match = self.childList.pop(remainTitles.index(title)) matchList.append((title, match)) remainTitles = [child.title() for child in self.childList] except ValueError: matchList.append((title, None)) newChildList = [] firstMiss = True for title, node in matchList: if not node: if (firstMiss and remainTitles and remainTitles[0].startswith(title)): # accept partial match on first miss for split tiles node = self.childList.pop(0) node.setTitle(title) else: node = TreeNode(newFormat) node.setTitle(title) node.setInitDefaultData() node.addSpotRef(self) treeStructure.addNodeDictRef(node) firstMiss = False newChildList.append(node) for child in self.childList: for oldNode in child.descendantGen(): if len(oldNode.spotRefs) <= 1: treeStructure.removeNodeDictRef(oldNode) else: oldNode.removeInvalidSpotRefs(False) self.childList = newChildList def replaceClonedBranches(self, origStruct): """Replace any duplicate IDs with clones from the given structure. Recursively search for duplicates. Arguments: origStruct -- the tree structure with the cloned nodes """ for i in range(len(self.childList)): if self.childList[i].uId in origStruct.nodeDict: self.childList[i] = origStruct.nodeDict[self.childList[i].uId] else: self.childList[i].replaceClonedBranches(origStruct) def loadChildNodeLevels(self, nodeList, initLevel=-1): """Recursively add children from a list of nodes and levels. Return True on success, False if data levels are not valid. Arguments: nodeList -- list of tuples with node and level initLevel -- the level of this node in the structure """ while nodeList: child, level = nodeList[0] if level == initLevel + 1: del nodeList[0] self.childList.append(child) if not child.loadChildNodeLevels(nodeList, level): return False else: return -1 < level <= initLevel return True def fieldSortKey(self, level=0): """Return a key used to sort by key fields. Arguments: level -- the sort key depth level for the current sort stage """ if len(self.formatRef.sortFields) > level: return self.formatRef.sortFields[level].sortKey(self) return ('',) def sortChildrenByField(self, recursive=True, forward=True): """Sort child nodes by predefined field keys. Arguments: recursive -- continue to sort recursively if true forward -- reverse the sort if false """ formats = set([child.formatRef for child in self.childList]) maxDepth = 0 directions = [] for nodeFormat in formats: if not nodeFormat.sortFields: nodeFormat.loadSortFields() maxDepth = max(maxDepth, len(nodeFormat.sortFields)) newDirections = [field.sortKeyForward for field in nodeFormat.sortFields] directions = [sum(i) for i in itertools.zip_longest(directions, newDirections, fillvalue= False)] if forward: directions = [bool(direct) for direct in directions] else: directions = [not bool(direct) for direct in directions] for level in range(maxDepth, 0, -1): self.childList.sort(key = operator.methodcaller('fieldSortKey', level - 1), reverse = not directions[level - 1]) if recursive: for child in self.childList: child.sortChildrenByField(True, forward) def titleSortKey(self): """Return a key used to sort by titles. """ return self.title().lower() def sortChildrenByTitle(self, recursive=True, forward=True): """Sort child nodes by titles. Arguments: recursive -- continue to sort recursively if true forward -- reverse the sort if false """ self.childList.sort(key = operator.methodcaller('titleSortKey'), reverse = not forward) if recursive: for child in self.childList: child.sortChildrenByTitle(True, forward) def updateNodeMathFields(self, treeFormats): """Recalculate math fields that depend on this node and so on. Return True if any data was changed. Arguments: treeFormats -- a ref to all of the formats """ changed = False for field in self.formatRef.fields(): for fieldRef in treeFormats.mathFieldRefDict.get(field.name, []): for node in fieldRef.dependentEqnNodes(self): if node.recalcMathField(fieldRef.eqnFieldName, treeFormats): changed = True return changed def recalcMathField(self, eqnFieldName, treeFormats): """Recalculate a math field, if changed, recalc depending math fields. Return True if any data was changed. Arguments: eqnFieldName -- the equation field in this node to update treeFormats -- a ref to all of the formats """ changed = False oldValue = self.data.get(eqnFieldName, '') newValue = self.formatRef.fieldDict[eqnFieldName].equationValue(self) if newValue != oldValue: self.data[eqnFieldName] = newValue changed = True for fieldRef in treeFormats.mathFieldRefDict.get(eqnFieldName, []): for node in fieldRef.dependentEqnNodes(self): node.recalcMathField(fieldRef.eqnFieldName, treeFormats) return changed def updateNumbering(self, fieldDict, currentSequence, levelLimit, completedClones, includeRoot=True, reserveNums=True, restartSetting=False): """Add auto incremented numbering to fields by type in the dict. Arguments: fieldDict -- numbering field name lists stored by type name currentSequence -- a list of int for the current numbering sequence levelLimit -- the number of child levels to include completedClones -- set of clone nodes already numbered includeRoot -- if Ture, number the current node reserveNums -- if true, increment number even without num field restartSetting -- if true, restart numbering after a no-field gap """ childSequence = currentSequence[:] if includeRoot: for fieldName in fieldDict.get(self.formatRef.name, []): self.data[fieldName] = '.'.join((repr(num) for num in currentSequence)) if self.formatRef.name in fieldDict or reserveNums: childSequence += [1] currentSequence[-1] += 1 if restartSetting and self.formatRef.name not in fieldDict: currentSequence[-1] = 1 if len(self.spotRefs) > 1: completedClones.add(self.uId) if levelLimit > 0: for child in self.childList: if len(child.spotRefs) > 1 and child.uId in completedClones: return child.updateNumbering(fieldDict, childSequence, levelLimit - 1, completedClones, True, reserveNums, restartSetting) def isIdentical(self, node, checkParents=True): """Return True if node format, data and descendants are identical. Also returns False if checkParents & the nodes have parents in common. Arguments: node -- the node to check """ if (self.formatRef != node.formatRef or len(self.childList) != len(node.childList) or self.data != node.data or (checkParents and not self.parents().isdisjoint(node.parents()))): return False for thisChild, otherChild in zip(self.childList, node.childList): if not thisChild.isIdentical(otherChild, False): return False return True def flatChildCategory(self, origFormats, structure): """Collapse descendant nodes by merging fields. Overwrites data in any fields with the same name. Arguments: origFormats -- copy of tree formats before any changes structure -- a ref to the tree structure """ thisSpot = self.spotByNumber(0) newChildList = [] for spot in thisSpot.spotDescendantOnlyGen(): if not spot.nodeRef.childList: oldParentSpot = spot.parentSpot while oldParentSpot != thisSpot: for field in origFormats[oldParentSpot.nodeRef.formatRef. name].fields(): data = oldParentSpot.nodeRef.data.get(field.name, '') if data: spot.nodeRef.data[field.name] = data spot.nodeRef.formatRef.addFieldIfNew(field.name, field.formatData()) oldParentSpot = oldParentSpot.parentSpot spot.parentSpot = thisSpot newChildList.append(spot.nodeRef) else: structure.removeNodeDictRef(spot.nodeRef) self.childList = newChildList def addChildCategory(self, catList, structure): """Insert category nodes above children. Arguments: catList -- the field names to add to the new level structure -- a ref to the tree structure """ newFormat = None catSet = set(catList) similarFormats = [nodeFormat for nodeFormat in structure.treeFormats.values() if catSet.issubset(set(nodeFormat.fieldNames()))] if similarFormats: similarFormat = min(similarFormats, key=lambda f: len(f.fieldDict)) if len(similarFormat.fieldDict) < len(self.childList[0]. formatRef.fieldDict): newFormat = similarFormat if not newFormat: newFormatName = '{0}_TYPE'.format(catList[0].upper()) num = 1 while newFormatName in structure.treeFormats: newFormatName = '{0}_TYPE_{1}'.format(catList[0].upper(), num) num += 1 newFormat = nodeformat.NodeFormat(newFormatName, structure.treeFormats) newFormat.addFieldList(catList, True, True) structure.treeFormats[newFormatName] = newFormat newParents = [] for child in self.childList: newParent = child.findEqualFields(catList, newParents) if not newParent: newParent = TreeNode(newFormat) for field in catList: data = child.data.get(field, '') if data: newParent.data[field] = data structure.addNodeDictRef(newParent) newParents.append(newParent) newParent.childList.append(child) self.childList = newParents for child in self.childList: child.removeInvalidSpotRefs(True, True) child.addSpotRef(self) def findEqualFields(self, fieldNames, nodes): """Return first node in nodes with same data in fieldNames as self. Arguments: fieldNames -- the list of fields to check nodes -- the nodes to search for a match """ for node in nodes: for field in fieldNames: if self.data.get(field, '') != node.data.get(field, ''): break else: # this for loop didn't hit break, so we have a match return node def exportTitleText(self, level=0): """Return a list of tabbed title lines for this node and descendants. Arguments: level -- indicates the indent level needed """ textList = ['\t' * level + self.title()] for child in self.childList: textList.extend(child.exportTitleText(level + 1)) return textList TreeLine-3.2.1/source/treeoutput.py000066400000000000000000000422751506556630100173370ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treeoutput.py, provides classes for output to views, html and printing # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import itertools from PyQt6.QtGui import QTextDocument import globalref _linkRe = re.compile(r']*href="#(.*?)"[^>]*>.*?', re.I | re.S) class OutputItem: """Class to store output for a single node. Stores text lines and original indent level. """ def __init__(self, spot, level): """Convert the spot's node into an output item. Create a blank item if spot is None. Arguments: spot -- the tree spot to convert level -- the node's original indent level """ if spot: node = spot.nodeRef nodeFormat = node.formatRef if not nodeFormat.useTables: self.textLines = [line + '
    ' for line in node.output(spotRef=spot)] else: self.textLines = node.output(keepBlanks=True, spotRef=spot) if not self.textLines: self.textLines = [''] self.addSpace = nodeFormat.spaceBetween self.siblingPrefix = nodeFormat.siblingPrefix self.siblingSuffix = nodeFormat.siblingSuffix if nodeFormat.useBullets and self.textLines: # remove
    extra space for bullets self.textLines[-1] = self.textLines[-1][:-6] self.uId = node.uId else: self.textLines = [''] self.addSpace = False self.siblingPrefix = '' self.siblingSuffix = '' self.uId = None self.level = level # following variables used by printdata only: self.height = 0 self.pageNum = 0 self.columnNum = 0 self.pagePos = 0 self.doc = None self.parentItem = None self.lastChildItem = None def duplicate(self): """Return an independent copy of this OutputItem. """ item = OutputItem(None, 0) item.textLines = self.textLines[:] item.addSpace = self.addSpace item.siblingPrefix = self.siblingPrefix item.siblingSuffix = self.siblingSuffix item.uId = self.uId item.level = self.level item.height = self.height item.pageNum = self.pageNum item.columnNum = self.columnNum item.pagePos = self.pagePos item.doc = None item.parentItem = self.parentItem item.lastChildItem = self.lastChildItem return item def addIndent(self, prevLevel, nextLevel): """Add
    tags to define indent levels in the output. Arguments: prevLevel -- the level of the previous item in the list nextLevel -- the level of the next item in the list """ for num in range(self.level - prevLevel): self.textLines[0] = '
    ' + self.textLines[0] for num in range(self.level - nextLevel): self.textLines[-1] += '
    ' def addAbsoluteIndent(self, pixels): """Add tags for an individual indentation. Removes the
    tag from the last line to avoid excess space, since
    starts a new line. The Qt output view does not fully support nested
    tags. Arguments: pixels -- the amount to indent """ self.textLines[0] = ('
    {1}'. format(pixels * self.level, self.textLines[0])) if not self.siblingPrefix and self.textLines[-1].endswith('
    '): self.textLines[-1] = self.textLines[-1][:-6] self.textLines[-1] += '
    ' def addSiblingPrefix(self): """Add the sibling prefix before this output. """ if self.siblingPrefix: self.textLines[0] = self.siblingPrefix + self.textLines[0] def addSiblingSuffix(self): """Add the sibling suffix after this output. """ if self.siblingSuffix: self.textLines[-1] += self.siblingSuffix def addAnchor(self): """Add a link anchor to this item. """ self.textLines[0] = '{1}'.format(self.uId, self.textLines[0]) def intLinkIds(self): """Return a set of uIDs from any internal links in this item. """ linkIds = set() for line in self.textLines: startPos = 0 while True: match = _linkRe.search(line, startPos) if not match: break uId = match.group(1) if uId: linkIds.add(uId) startPos = match.start(1) return linkIds def numLines(self): """Return the number of text lines in the item. """ return len(self.textLines) def equalPrefix(self, otherItem): """Return True if sibling prefixes and suffixes are equal. Arguments: otherItem -- the item to compare """ return (self.siblingPrefix == otherItem.siblingPrefix and self.siblingSuffix == otherItem.siblingSuffix) def setDocHeight(self, paintDevice, width, printFont, replaceDoc=False): """Set the height of this item for use in printer output. Creates an output document if not already created. Arguments: paintDevice -- the printer or other device for settings width -- the width available for the output text printFont -- the default font for the document replaceDoc -- if true, re-create the text document """ if not self.doc or replaceDoc: self.doc = QTextDocument() lines = '\n'.join(self.textLines) if lines.endswith('
    '): # remove trailing
    tag to avoid excess space lines = lines[:-6] self.doc.setHtml(lines) self.doc.setDefaultFont(printFont) frameFormat = self.doc.rootFrame().frameFormat() frameFormat.setBorder(0) frameFormat.setMargin(0) frameFormat.setPadding(0) self.doc.rootFrame().setFrameFormat(frameFormat) layout = self.doc.documentLayout() layout.setPaintDevice(paintDevice) self.doc.setTextWidth(width) self.height = layout.documentSize().height() def splitDocHeight(self, initHeight, maxHeight, paintDevice, width, printFont): """Split this item into two items and return them. The first item will fit into initHeight if practical. Splits at line endings if posible. Arguments: initHeight -- the preferred height of the first page maxheight -- the max height of any pages paintDevice -- the printer or other device for settings width -- the width available for the output text printFont -- the default font for the document """ newItem = self.duplicate() fullHeight = self.height lines = '\n'.join(self.textLines) allLines = [line + '
    ' for line in lines.split('
    ')] self.textLines = [] prevHeight = 0 for line in allLines: self.textLines.append(line) self.setDocHeight(paintDevice, width, printFont, True) if ((prevHeight and self.height > initHeight and fullHeight - prevHeight > maxHeight) or (prevHeight and self.height > maxHeight)): self.textLines = self.textLines[:-1] self.setDocHeight(paintDevice, width, printFont, True) newItem.textLines = allLines[len(self.textLines):] newItem.setDocHeight(paintDevice, width, printFont, True) return (self, newItem) if self.height > maxHeight: break prevHeight = self.height # no line ending breaks found text = ' \n'.join(allLines) allWords = [word + ' ' for word in text.split(' ')] newWords = [] prevHeight = 0 for word in allWords: if word.strip() == ' initHeight and fullHeight - prevHeight < maxHeight) or (prevHeight and self.height > maxHeight)): self.textLines = [''.join(newWords[:-1])] self.setDocHeight(paintDevice, width, printFont, True) newItem.textLines = [''.join(allWords[len(newWords):])] newItem.setDocHeight(paintDevice, width, printFont, True) return (self, newItem) if self.height > maxHeight: break prevHeight = self.height newItem.setDocHeight(paintDevice, width, printFont, True) return (newItem, None) # fail to split class OutputGroup(list): """A list of OutputItems that takes TreeNodes as input. Modifies the output text for use in views, html and printing. """ def __init__(self, spotList, includeRoot=True, includeDescend=False, openOnly=False): """Convert the node iter list into a list of output items. Arguments: spotList -- a list of spots to convert to output includeRoot -- if True, include the nodes in nodeList includeDescend -- if True, include children, grandchildren, etc. openOnly -- if true, ignore collapsed children in the main treeView """ super().__init__() for spot in spotList: level = -1 if includeRoot: level = 0 self.append(OutputItem(spot, level)) if includeDescend: self.addChildren(spot, level, openOnly) def addChildren(self, spot, level, openOnly=False): """Recursively add OutputItems for descendants of the given spot. Arguments: spot -- the parent tree spot level -- the parent node's original indent level """ treeView = globalref.mainControl.activeControl.activeWindow.treeView if not openOnly or treeView.isSpotExpanded(spot): for child in spot.childSpots(): self.append(OutputItem(child, level + 1)) self.addChildren(child, level + 1, openOnly) def addIndents(self): """Add nested
    elements to define indentations in the output. """ prevLevel = 0 for item, nextItem in itertools.zip_longest(self, self[1:]): try: nextLevel = nextItem.level except AttributeError: nextLevel = 0 item.addIndent(prevLevel, nextLevel) prevLevel = item.level def addAbsoluteIndents(self, pixels=20): """Add tags for individual indentation on each node. The Qt output view does not fully support nested
    tags. Arguments: pixels -- the amount to indent """ for item in self: item.addAbsoluteIndent(pixels) def addBlanksBetween(self): """Add blank lines between nodes based on node format's spaceBetween. """ for item, nextItem in zip(self, self[1:]): if item.addSpace or nextItem.addSpace: item.textLines[-1] += '
    ' def addAnchors(self, extraLevels=0): """Add anchors to items that are targets and to low level items. Arguments: extraLevels -- force adding anchors if level < this """ linkIds = set() for item in self: linkIds.update(item.intLinkIds()) for item in self: if item.uId in linkIds or item.level < extraLevels: item.addAnchor() def hasPrefixes(self): """Return True if sibling prefixes or suffixes are found. """ return bool([item for item in self if item.siblingPrefix or item.siblingSuffix]) def addSiblingPrefixes(self): """Add sibling prefixes and suffixes for each node. """ if not self.hasPrefixes(): return addPrefix = True for item, nextItem in itertools.zip_longest(self, self[1:]): if addPrefix: item.addSiblingPrefix() if (not nextItem or item.level != nextItem.level or not item.equalPrefix(nextItem)): item.addSiblingSuffix() addPrefix = True else: addPrefix = False def combineAllSiblings(self): """Group all sibling items with the same prefix into single items. Also add sibling prefixes and suffixes and spaces in between. """ newItems = [] prevItem = None for item in self: if prevItem: if item.level == prevItem.level and item.equalPrefix(prevItem): if item.addSpace or prevItem.addSpace: prevItem.textLines[-1] += '
    ' prevItem.textLines.extend(item.textLines) else: prevItem.addSiblingSuffix() newItems.append(prevItem) item.addSiblingPrefix() prevItem = item else: item.addSiblingPrefix() prevItem = item prevItem.addSiblingSuffix() newItems.append(prevItem) self[:] = newItems def combineLines(self, addSpacing=True, addPrefixes=True): """Return an OutputItem including all of the text from all items. Arguments: addPrefixes -- if True, add sibling prefix and suffix to result addSpacing -- if True, add spacing between items with addSpace True """ comboItem = self[0].duplicate() for item in self[1:]: if item.addSpace: comboItem.textLines[-1] += '
    ' comboItem.textLines.extend(item.textLines) if addPrefixes: comboItem.addSiblingPrefix() comboItem.addSiblingSuffix() return comboItem def splitColumns(self, numColumns): """Split output into even length columns using number of lines. Return a list with a group for each column. Arguments: numColumns - the number of columns to split """ if numColumns < 2: return [self] groupList = [] if len(self) <= numColumns: for item in self: groupList.append(OutputGroup([])) groupList[-1].append(item) return groupList numEach = len(self) // numColumns for colNum in range(numColumns - 1): groupList.append(OutputGroup([])) groupList[-1].extend(self[colNum * numEach : (colNum + 1) * numEach]) groupList.append(OutputGroup([])) groupList[-1].extend(self[(numColumns - 1) * numEach : ]) numChanges = 1 while numChanges: numChanges = 0 for colNum in range(numColumns - 1): if (groupList[colNum].totalNumLines() > groupList[colNum + 1]. totalNumLines() + groupList[colNum][-1].numLines()): groupList[colNum + 1].insert(0, groupList[colNum][-1]) del groupList[colNum][-1] numChanges += 1 if (groupList[colNum].totalNumLines() + groupList[colNum + 1][0].numLines() <= groupList[colNum + 1].totalNumLines()): groupList[colNum].append(groupList[colNum + 1][0]) del groupList[colNum + 1][0] numChanges += 1 return groupList def getLines(self): """Return the full list of text lines from this group. """ if not self: return [] lines = [] for item in self: lines.extend(item.textLines) return lines def totalNumLines(self): """Return the total number of lines of all items in this container. """ return sum([item.numLines() for item in self]) def loadFamilyRefs(self): """Set parentItem and lastChildItem for all items. Used by the printdata class. """ recentParents = [None] for item in self: if item.level > 0: item.parentItem = recentParents[item.level - 1] item.parentItem.lastChildItem = item try: recentParents[item.level] = item except IndexError: recentParents.append(item) TreeLine-3.2.1/source/treeselection.py000066400000000000000000000231111506556630100177500ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treeselection.py, provides a class for the tree view's selection model # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import collections import json from PyQt6.QtCore import QItemSelectionModel, QMimeData from PyQt6.QtGui import QClipboard from PyQt6.QtWidgets import QApplication import treestructure import treespotlist import globalref _maxHistoryLength = 10 class TreeSelection(QItemSelectionModel): """Class override for the tree view's selection model. Provides methods for easier access to selected nodes. """ def __init__(self, model, parent=None): """Initialize the selection model. Arguments: model -- the model for view data parent -- the parent tree view """ super().__init__(model, parent) self.modelRef = model self.tempExpandedSpots = [] self.prevSpots = [] self.nextSpots = [] self.restoreFlag = False self.selectionChanged.connect(self.updateSelectLists) def selectedCount(self): """Return the number of selected spots. """ return len(self.selectedIndexes()) def selectedSpots(self): """Return a SpotList of selected spots, sorted in tree order. """ return treespotlist.TreeSpotList([index.internalPointer() for index in self.selectedIndexes()]) def selectedBranchSpots(self): """Return a SpotList of spots at the top of selected branches. Remvoves any duplicate spots that are already covered by the branches. """ spots = self.selectedSpots() spotSet = set(spots) return treespotlist.TreeSpotList([spot for spot in spots if spot.parentSpotSet(). isdisjoint(spotSet)]) def selectedNodes(self): """Return a list of the currently selected tree nodes. Removes any duplicate (cloned) nodes. """ tmpDict = collections.OrderedDict() for spot in self.selectedSpots(): node = spot.nodeRef tmpDict[node.uId] = node return list(tmpDict.values()) def selectedBranches(self): """Return a list of nodes at the top of selected branches. Remvoves any duplicates that are already covered by the branches. """ tmpDict = collections.OrderedDict() for spot in self.selectedBranchSpots(): node = spot.nodeRef tmpDict[node.uId] = node return list(tmpDict.values()) def currentSpot(self): """Return the current tree spot. Can raise AttributeError if no spot is current. """ return self.currentIndex().internalPointer() def currentNode(self): """Return the current tree node. Can raise AttributeError if no node is current. """ return self.currentSpot().nodeRef def selectSpots(self, spotList, signalUpdate=True, expandParents=False): """Clear the current selection and select the given spots. Arguments: spotList -- the spots to select signalUpdate -- if False, block normal select update signals expandParents -- open parent spots to make selection visible """ if expandParents: treeView = (globalref.mainControl.activeControl.activeWindow. treeView) for spot in self.tempExpandedSpots: treeView.collapseSpot(spot) self.tempExpandedSpots = [] for spot in spotList: parent = spot.parentSpot while parent.parentSpot: if not treeView.isSpotExpanded(parent): treeView.expandSpot(parent) self.tempExpandedSpots.append(parent) parent = parent.parentSpot if not signalUpdate: self.blockSignals(True) self.addToHistory(spotList) self.clear() if spotList: for spot in spotList: self.select(spot.index(self.modelRef), QItemSelectionModel.SelectionFlag.Select) self.setCurrentIndex(spotList[0].index(self.modelRef), QItemSelectionModel.SelectionFlag.Current) self.blockSignals(False) def selectNodeById(self, nodeId): """Select the first spot from the given node ID. Return True on success. Arguments: nodeId -- the ID of the node to select """ try: node = self.modelRef.treeStructure.nodeDict[nodeId] self.selectSpots([node.spotByNumber(0)], True, True) except KeyError: return False return True def setCurrentSpot(self, spot): """Set the current spot. Arguments: spot -- the spot to make current """ self.blockSignals(True) self.setCurrentIndex(spot.index(self.modelRef), QItemSelectionModel.SelectionFlag.Current) self.blockSignals(False) def copySelectedNodes(self): """Copy these node branches to the clipboard. """ nodes = self.selectedBranches() if not nodes: return clip = QApplication.clipboard() if clip.supportsSelection(): titleList = [] for node in nodes: titleList.extend(node.exportTitleText()) clip.setText('\n'.join(titleList), QClipboard.Mode.Selection) struct = treestructure.TreeStructure(topNodes=nodes, addSpots=False) generics = {formatRef.genericType for formatRef in struct.treeFormats.values() if formatRef.genericType} for generic in generics: genericRef = self.modelRef.treeStructure.treeFormats[generic] struct.treeFormats.addTypeIfMissing(genericRef) for formatRef in genericRef.derivedTypes: struct.treeFormats.addTypeIfMissing(formatRef) data = struct.fileData() dataStr = json.dumps(data, indent=0, sort_keys=True) mime = QMimeData() mime.setData('application/json', bytes(dataStr, encoding='utf-8')) clip.setMimeData(mime) def restorePrevSelect(self): """Go back to the most recent saved selection. """ self.validateHistory() if len(self.prevSpots) > 1: del self.prevSpots[-1] oldSelect = self.selectedSpots() if oldSelect and (not self.nextSpots or oldSelect != self.nextSpots[-1]): self.nextSpots.append(oldSelect) self.restoreFlag = True self.selectSpots(self.prevSpots[-1], expandParents=True) self.restoreFlag = False def restoreNextSelect(self): """Go forward to the most recent saved selection. """ self.validateHistory() if self.nextSpots: select = self.nextSpots.pop(-1) if select and (not self.prevSpots or select != self.prevSpots[-1]): self.prevSpots.append(select) self.restoreFlag = True self.selectSpots(select, expandParents=True) self.restoreFlag = False def addToHistory(self, spots): """Add given spots to previous select list. Arguments: spots -- a list of spots to be added """ if spots and not self.restoreFlag and (not self.prevSpots or spots != self.prevSpots[-1]): self.prevSpots.append(spots) if len(self.prevSpots) > _maxHistoryLength: del self.prevSpots[:2] self.nextSpots = [] def validateHistory(self): """Clear invalid items from history lists. """ for histList in (self.prevSpots, self.nextSpots): for spots in histList: spots[:] = [spot for spot in spots if spot.isValid()] histList[:] = [spots for spots in histList if spots] def updateSelectLists(self): """Update history after a selection change. """ self.addToHistory(self.selectedSpots()) def selectTitleMatch(self, searchText, forward=True, includeCurrent=False): """Select a node with a title matching the search text. Returns True if found, otherwise False. Arguments: searchText -- the text to look for forward -- next if True, previous if False includeCurrent -- look in current node if True """ searchText = searchText.lower() currentSpot = self.currentSpot() spot = currentSpot while True: if not includeCurrent: if forward: spot = spot.nextTreeSpot(True) else: spot = spot.prevTreeSpot(True) if spot is currentSpot: return False includeCurrent = False if searchText in spot.nodeRef.title().lower(): self.selectSpots([spot], True, True) return True TreeLine-3.2.1/source/treespot.py000066400000000000000000000204151506556630100167540ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treespot.py, provides a class to store locations of tree node instances # # TreeLine, an information storage program # Copyright (C) 2018, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import sys import operator class TreeSpot: """Class to store location info for tree node instances. Used to generate breadcrumb navigation and interface with tree views. A spot without a parent spot is an imaginary root spot, wihout a real node. """ def __init__(self, nodeRef, parentSpot): """Initialize a tree spot. Arguments: nodeRef -- reference to the associated tree node parentSpot -- the parent TreeSpot object """ self.nodeRef = nodeRef self.parentSpot = parentSpot def index(self, modelRef): """Returns the index of this spot in the tree model. Arguments: modelRef -- a ref to the tree model """ return modelRef.createIndex(self.row(), 0, self) def row(self): """Return the rank of this spot in its parent's child list. Should never be called from the imaginary root spot. """ try: return self.parentSpot.nodeRef.childList.index(self.nodeRef) except ValueError: return 0 # avoid error message from interim view updates def instanceNumber(self): """Return this spot's rank in the node's spot list. """ spotList = sorted(list(self.nodeRef.spotRefs), key=operator.methodcaller('sortKey')) return spotList.index(self) def spotId(self): """Return a spot ID string, in the form "nodeID:spotInstance". """ return '{0}:{1:d}'.format(self.nodeRef.uId, self.instanceNumber()) def isValid(self): """Return True if spot references and all parents are valid. """ spot = self while spot.parentSpot: if not (spot in spot.nodeRef.spotRefs and spot.nodeRef in spot.parentSpot.nodeRef.childList): return False spot = spot.parentSpot if not spot in spot.nodeRef.spotRefs: return False return True def spotDescendantGen(self): """Return a generator to step through all spots in this branch. Includes self. """ yield self for childSpot in self.childSpots(): for spot in childSpot.spotDescendantGen(): yield spot def spotDescendantOnlyGen(self): """Return a generator to step through the spots in this branch. Does not include self. """ for childSpot in self.childSpots(): yield childSpot for spot in childSpot.spotDescendantGen(): yield spot def expandedSpotDescendantGen(self, treeView): """Return a generator to step through expanded spots in this branch. Does not include root spot. Arguments: treeView -- a ref to the treeview """ for childSpot in self.childSpots(): if treeView.isSpotExpanded(childSpot): yield childSpot for spot in childSpot.expandedSpotDescendantGen(treeView): yield spot def levelSpotDescendantGen(self, treeView, includeRoot=True, maxLevel=None, openOnly=False, initLevel=0): """Return generator with (spot, level) tuples for this branch. Arguments: treeView -- a ref to the treeview, requiired to check if open includeRoot -- if True, the root spot is included maxLevel -- the max number of levels to return (no limit if none) openOnly -- if True, only include children open in the given view initLevel -- the level number to start with """ if maxLevel == None: maxLevel = sys.maxsize if includeRoot: yield (self, initLevel) initLevel += 1 if initLevel < maxLevel and (not openOnly or treeView.isSpotExpanded(self)): for childSpot in self.childSpots(): for spot, level in childSpot.levelSpotDescendantGen(treeView, True, maxLevel, openOnly, initLevel): yield (spot, level) def childSpots(self): """Return a list of immediate child spots. """ return [childNode.matchedSpot(self) for childNode in self.nodeRef.childList] def prevSiblingSpot(self): """Return the nearest previous sibling spot or None. """ if self.parentSpot: pos = self.row() if pos > 0: node = self.parentSpot.nodeRef.childList[pos - 1] return node.matchedSpot(self.parentSpot) return None def nextSiblingSpot(self): """Return the nearest next sibling spot or None. """ if self.parentSpot: childList = self.parentSpot.nodeRef.childList pos = self.row() + 1 if pos < len(childList): return childList[pos].matchedSpot(self.parentSpot) return None def prevTreeSpot(self, loop=False): """Return the previous node in the tree order. Return None at the start of the tree unless loop is true. Arguments: loop -- return the last node of the tree after the first if true """ sibling = self.prevSiblingSpot() if sibling: return sibling.lastDescendantSpot() if self.parentSpot.parentSpot: return self.parentSpot elif loop: return self.rootSpot().lastDescendantSpot() return None def nextTreeSpot(self, loop=False): """Return the next node in the tree order. Return None at the end of the tree unless loop is true. Arguments: loop -- return the root node at the end of the tree if true """ if self.nodeRef.childList: return self.nodeRef.childList[0].matchedSpot(self) ancestor = self while ancestor.parentSpot: sibling = ancestor.nextSiblingSpot() if sibling: return sibling ancestor = ancestor.parentSpot if loop: return ancestor.nodeRef.childList[0].matchedSpot(ancestor) return None def lastDescendantSpot(self): """Return the last spot of this spots's branch (last in tree order). """ spot = self while spot.nodeRef.childList: spot = spot.nodeRef.childList[-1].matchedSpot(spot) return spot def spotChain(self): """Return a list of parent spots, including self. """ chain = [] spot = self while spot.parentSpot: chain.insert(0, spot) spot = spot.parentSpot return chain def parentSpotSet(self): """Return a set of ancestor spots, not including self. """ result = set() spot = self.parentSpot while spot.parentSpot: result.add(spot) spot = spot.parentSpot return result def rootSpot(self): """Return the root spot that references the tree structure. """ spot = self while spot.parentSpot: spot = spot.parentSpot return spot def sortKey(self): """Return a tuple of parent row positions for sorting in tree order. """ positions = [] spot = self while spot.parentSpot: positions.insert(0, spot.row()) spot = spot.parentSpot return tuple(positions) TreeLine-3.2.1/source/treespotlist.py000066400000000000000000000301531506556630100176500ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treespotlist.py, provides a class to do operations on groups of spots # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import collections import operator from PyQt6.QtWidgets import QApplication import treestructure import undo class TreeSpotList(list): """Class to do operations on groups of spots. Stores a list of nodes. """ def __init__(self, spotList=None, sortSpots=True): """Initialize a tree spot group. Arguments: spotList -- the initial list of spots sortSpots -- if True sort the spots in tree order """ super().__init__() if spotList: self[:] = spotList if sortSpots: self.sort(key=operator.methodcaller('sortKey')) def relatedNodes(self): """Return a list of nodes related to these spots. Removes any duplicate (cloned) nodes. """ tmpDict = collections.OrderedDict() for spot in self: node = spot.nodeRef tmpDict[node.uId] = node return list(tmpDict.values()) def pasteChild(self, treeStruct, treeView): """Paste child nodes from the clipbaord. Return True on success. Arguments: treeStruct -- a ref to the existing tree structure treeView -- a ref to the tree view for expanding nodes """ mimeData = QApplication.clipboard().mimeData() parentNodes = self.relatedNodes() if not parentNodes: parentNodes = [treeStruct] undoObj = undo.ChildListUndo(treeStruct.undoList, parentNodes, treeFormats=treeStruct.treeFormats) for parent in parentNodes: newStruct = treestructure.structFromMimeData(mimeData) if not newStruct: treeStruct.undoList.removeLastUndo(undoObj) return False newStruct.replaceDuplicateIds(treeStruct.nodeDict) treeStruct.addNodesFromStruct(newStruct, parent) for spot in self: treeView.expandSpot(spot) return True def pasteSibling(self, treeStruct, insertBefore=True): """Paste a sibling at the these spots. Return True on success. Arguments: treeStruct -- a ref to the existing tree structure insertBefore -- if True, insert before these nodes, o/w after """ mimeData = QApplication.clipboard().mimeData() parentNodes = [spot.parentSpot.nodeRef for spot in self] undoObj = undo.ChildListUndo(treeStruct.undoList, parentNodes, treeFormats=treeStruct.treeFormats) for spot in self: newStruct = treestructure.structFromMimeData(mimeData) if not newStruct: treeStruct.undoList.removeLastUndo(undoObj) return False newStruct.replaceDuplicateIds(treeStruct.nodeDict) parent = spot.parentSpot.nodeRef pos = parent.childList.index(spot.nodeRef) if not insertBefore: pos += 1 treeStruct.addNodesFromStruct(newStruct, parent, pos) return True def pasteCloneChild(self, treeStruct, treeView): """Paste child clones from the clipbaord. Return True on success. Arguments: treeStruct -- a ref to the existing tree structure treeView -- a ref to the tree view for expanding nodes """ mimeData = QApplication.clipboard().mimeData() newStruct = treestructure.structFromMimeData(mimeData) if not newStruct: return False try: existNodes = [treeStruct.nodeDict[node.uId] for node in newStruct.childList] except KeyError: return False # nodes copied from other file parentNodes = self.relatedNodes() if not parentNodes: parentNodes = [treeStruct] for parent in parentNodes: if not parent.ancestors().isdisjoint(set(existNodes)): return False # circular ref for node in existNodes: if parent in node.parents(): return False # identical siblings undoObj = undo.ChildListUndo(treeStruct.undoList, parentNodes, treeFormats=treeStruct.treeFormats) for parent in parentNodes: for node in existNodes: parent.childList.append(node) node.addSpotRef(parent) for spot in self: treeView.expandSpot(spot) return True def pasteCloneSibling(self, treeStruct, insertBefore=True): """Paste sibling clones at the these spots. Return True on success. Arguments: treeStruct -- a ref to the existing tree structure insertBefore -- if True, insert before these nodes, o/w after """ mimeData = QApplication.clipboard().mimeData() newStruct = treestructure.structFromMimeData(mimeData) if not newStruct: return False try: existNodes = [treeStruct.nodeDict[node.uId] for node in newStruct.childList] except KeyError: return False # nodes copied from other file parentNodes = [spot.parentSpot.nodeRef for spot in self] for parent in parentNodes: if not parent.ancestors().isdisjoint(set(existNodes)): return False # circular ref for node in existNodes: if parent in node.parents(): return False # identical siblings undoObj = undo.ChildListUndo(treeStruct.undoList, parentNodes, treeFormats=treeStruct.treeFormats) for spot in self: parent = spot.parentSpot.nodeRef pos = parent.childList.index(spot.nodeRef) if not insertBefore: pos += 1 for node in existNodes: parent.childList.insert(pos, node) node.addSpotRef(parent) return True def addChild(self, treeStruct, treeView): """Add new child to these spots. Return the new spots. Arguments: treeStruct -- a ref to the existing tree structure treeView -- a ref to the tree view for expanding nodes """ selSpots = self if not selSpots: selSpots = list(treeStruct.spotRefs) undo.ChildListUndo(treeStruct.undoList, [spot.nodeRef for spot in selSpots]) newSpots = [] for spot in selSpots: newNode = spot.nodeRef.addNewChild(treeStruct) newSpots.append(newNode.matchedSpot(spot)) if spot.parentSpot: # can't expand root struct spot treeView.expandSpot(spot) return newSpots def insertSibling(self, treeStruct, insertBefore=True): """Insert a new sibling node at these nodes. Return the new spots. Arguments: treeStruct -- a ref to the existing tree structure insertBefore -- if True, insert before these nodes, o/w after """ undo.ChildListUndo(treeStruct.undoList, [spot.parentSpot.nodeRef for spot in self]) newSpots = [] for spot in self: newNode = spot.parentSpot.nodeRef.addNewChild(treeStruct, spot.nodeRef, insertBefore) newSpots.append(newNode.matchedSpot(spot.parentSpot)) return newSpots def delete(self, treeStruct): """Delete these spots, return a new spot to select. Arguments: treeStruct -- a ref to the existing tree structure """ # gather next selected node in decreasing order of desirability nextSel = [spot.nextSiblingSpot() for spot in self] nextSel.extend([spot.prevSiblingSpot() for spot in self]) nextSel.extend([spot.parentSpot for spot in self]) while (not nextSel[0] or not nextSel[0].parentSpot or nextSel[0] in self): del nextSel[0] spotSet = set(self) branchSpots = [spot for spot in self if spot.parentSpotSet().isdisjoint(spotSet)] undoParents = {spot.parentSpot.nodeRef for spot in branchSpots} undo.ChildListUndo(treeStruct.undoList, list(undoParents)) for spot in branchSpots: treeStruct.deleteNodeSpot(spot) return nextSel[0] def indent(self, treeStruct): """Indent these spots. Makes them children of their previous siblings. Return the new spots. Arguments: treeStruct -- a ref to the existing tree structure """ undoSpots = ([spot.parentSpot for spot in self] + [spot.prevSiblingSpot() for spot in self]) undo.ChildListUndo(treeStruct.undoList, [spot.nodeRef for spot in undoSpots]) newSpots = [] for spot in self: node = spot.nodeRef newParentSpot = spot.prevSiblingSpot() node.changeParent(spot.parentSpot, newParentSpot) newSpots.append(node.matchedSpot(newParentSpot)) return newSpots def unindent(self, treeStruct): """Unindent these spots. Makes them their parent's next sibling. Return the new spots. Arguments: treeStruct -- a ref to the existing tree structure """ undoSpots = [spot.parentSpot for spot in self] undoSpots.extend([spot.parentSpot for spot in undoSpots]) undo.ChildListUndo(treeStruct.undoList, [spot.nodeRef for spot in undoSpots]) newSpots = [] for spot in reversed(self): node = spot.nodeRef oldParentSpot = spot.parentSpot newParentSpot = oldParentSpot.parentSpot pos = (newParentSpot.nodeRef.childList.index(oldParentSpot.nodeRef) + 1) node.changeParent(oldParentSpot, newParentSpot, pos) newSpots.append(node.matchedSpot(newParentSpot)) return newSpots def move(self, treeStruct, up=True): """Move these spots up or down by one item. Arguments: treeStruct -- a ref to the existing tree structure up -- if True move up, o/w down """ undo.ChildListUndo(treeStruct.undoList, [spot.parentSpot.nodeRef for spot in self]) if not up: self.reverse() for spot in self: parent = spot.parentSpot.nodeRef pos = parent.childList.index(spot.nodeRef) del parent.childList[pos] pos = pos - 1 if up else pos + 1 parent.childList.insert(pos, spot.nodeRef) def moveToEnd(self, treeStruct, first=True): """Move these spots to the first or last position. Arguments: treeStruct -- a ref to the existing tree structure first -- if True move to first position, o/w last """ undo.ChildListUndo(treeStruct.undoList, [spot.parentSpot.nodeRef for spot in self]) if first: self.reverse() for spot in self: parent = spot.parentSpot.nodeRef parent.childList.remove(spot.nodeRef) if first: parent.childList.insert(0, spot.nodeRef) else: parent.childList.append(spot.nodeRef) TreeLine-3.2.1/source/treestructure.py000066400000000000000000000314751506556630100200370ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treestructure.py, provides a class to store the tree's data # # TreeLine, an information storage program # Copyright (C) 2018, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import operator import copy import json import uuid import treenode import treeformats import undo try: from __main__ import __version__ except ImportError: __version__ = '' defaultRootTitle = _('Main') class TreeStructure(treenode.TreeNode): """Class to store all tree data. Inherits TreeNode to get childList (holds top nodes) and other methods. """ def __init__(self, fileData=None, topNodes=None, addDefaults=False, addSpots=True): """Create and store a tree structure from file data. If no file data is given, create an empty or a default new structure. Arguments: fileData -- a dict in JSON file format of a structure topNodes -- existing top-level nodes to add to a structure addDefaults -- if True, adds default new structure addSpots -- if True, adds parent spot references """ super().__init__(None) # init TreeNode, with no formatRef self.nodeDict = {} self.undoList = None self.redoList = None self.configDialogFormats = None self.mathZeroBlanks = True self.childRefErrorNodes = [] if fileData: self.treeFormats = treeformats.TreeFormats(fileData['formats']) self.treeFormats.loadGlobalSavedConditions(fileData['properties']) for nodeInfo in fileData['nodes']: formatRef = self.treeFormats[nodeInfo['format']] node = treenode.TreeNode(formatRef, nodeInfo) self.nodeDict[node.uId] = node for node in self.nodeDict.values(): node.assignRefs(self.nodeDict) if node.tmpChildRefs: self.childRefErrorNodes.append(node) node.tmpChildRefs = [] for uId in fileData['properties']['topnodes']: node = self.nodeDict[uId] self.childList.append(node) if 'zeroblanks' in fileData['properties']: self.mathZeroBlanks = fileData['properties']['zeroblanks'] if addSpots: self.generateSpots(None) elif topNodes: self.childList = topNodes self.treeFormats = treeformats.TreeFormats() for topNode in topNodes: for node in topNode.descendantGen(): self.nodeDict[node.uId] = node self.treeFormats.addTypeIfMissing(node.formatRef) if addSpots: self.generateSpots(None) elif addDefaults: self.treeFormats = treeformats.TreeFormats(setDefault=True) node = treenode.TreeNode(self.treeFormats[treeformats. defaultTypeName]) node.setTitle(defaultRootTitle) self.nodeDict[node.uId] = node self.childList.append(node) if addSpots: self.generateSpots(None) else: self.treeFormats = treeformats.TreeFormats() self.fileInfoNode = treenode.TreeNode(self.treeFormats.fileInfoFormat) def fileData(self): """Return a fileData dict in JSON file format. """ formats = self.treeFormats.storeFormats() nodeList = sorted([node.fileData() for node in self.nodeDict.values()], key=operator.itemgetter('uid')) topNodeIds = [node.uId for node in self.childList] properties = {'tlversion': __version__, 'topnodes': topNodeIds} self.treeFormats.storeGlobalSavedConditions(properties) if not self.mathZeroBlanks: properties['zeroblanks'] = False fileData = {'formats': formats, 'nodes': nodeList, 'properties': properties} return fileData def purgeOldFieldData(self): """Remove data from obsolete fields from all nodes. """ fieldSets = self.treeFormats.fieldNameDict() for node in self.nodeDict.values(): oldKeys = set(node.data.keys()) - fieldSets[node.formatRef.name] for key in oldKeys: del node.data[key] def addNodeDictRef(self, node): """Add the given node to the node dictionary. Arguments: node -- the node to add """ self.nodeDict[node.uId] = node def removeNodeDictRef(self, node): """Remove the given node from the node dictionary. Arguments: node -- the node to remove """ try: del self.nodeDict[node.uId] except KeyError: pass def rebuildNodeDict(self): """Remove and re-create the entire node dictionary. """ self.nodeDict = {} for node in self.descendantGen(): self.nodeDict[node.uId] = node def replaceAllSpots(self, removeUnusedNodes=True): """Remove and regenerate all spot refs for the tree. Arguments: removeUnusedNodes -- if True, delete refs to nodes without spots """ self.spotRefs = set() for node in self.nodeDict.values(): node.spotRefs = set() self.generateSpots(None) if removeUnusedNodes: self.nodeDict = {uId:node for (uId, node) in self.nodeDict.items() if node.spotRefs} def deleteNodeSpot(self, spot): """Remove the given spot, removing the entire node if no spots remain. Arguments: spot -- the spot to remove """ spot.parentSpot.nodeRef.childList.remove(spot.nodeRef) for node in spot.nodeRef.descendantGen(): if len(node.spotRefs) <= 1: self.removeNodeDictRef(node) node.spotRefs = set() else: node.removeInvalidSpotRefs(False) def structSpot(self): """Return the top spot (not tied to a node). """ (topSpot, ) = self.spotRefs return topSpot def rootSpots(self): """Return a list of spots from root nodes. """ (topSpot, ) = self.spotRefs return topSpot.childSpots() def spotById(self, spotId): """Return a spot based on a spot ID string. Raises KeyError on invalid node ID, an IndexError on invalid spot num. Arguments: spotId -- a spot ID string, in the form "nodeID:spotInstance" """ nodeId, spotNum = spotId.split(':', 1) return self.nodeDict[nodeId].spotByNumber(int(spotNum)) def descendantGen(self): """Return a generator to step through all nodes in tree order. Override from TreeNode to exclude self. """ for child in self.childList: for node in child.descendantGen(): yield node def getConfigDialogFormats(self, forceReset=False): """Return duplicate formats for use in the config dialog. Arguments: forceReset -- if True, sets duplicate formats back to original """ if not self.configDialogFormats or forceReset: self.configDialogFormats = copy.deepcopy(self.treeFormats) return self.configDialogFormats def applyConfigDialogFormats(self, addUndo=True): """Replace the formats with the duplicates and signal for view update. Also updates all nodes for changed type and field names. """ if addUndo: undo.FormatUndo(self.undoList, self.treeFormats, self.configDialogFormats) self.treeFormats.copySettings(self.configDialogFormats) self.treeFormats.updateDerivedRefs() self.treeFormats.updateMathFieldRefs() if self.configDialogFormats.fieldRenameDict: for node in self.nodeDict.values(): fieldRenameDict = (self.configDialogFormats.fieldRenameDict. get(node.formatRef.name, {})) tmpDataDict = {} for oldName, newName in fieldRenameDict.items(): if oldName in node.data: tmpDataDict[newName] = node.data[oldName] del node.data[oldName] node.data.update(tmpDataDict) self.configDialogFormats.fieldRenameDict = {} if self.treeFormats.emptiedMathDict: for node in self.nodeDict.values(): for fieldName in self.treeFormats.emptiedMathDict.get(node. formatRef. name, set()): node.data.pop(fieldName, None) self.formats.emptiedMathDict = {} def usesType(self, typeName): """Return true if any nodes use the give node format type. Arguments: typeName -- the format name to search for """ for node in self.nodeDict.values(): if node.formatRef.name == typeName: return True return False def replaceDuplicateIds(self, duplicateDict): """Generate new unique IDs for any nodes found in newNodeDict. Arguments: newNodeDict -- a dict to search for duplicates """ for node in list(self.nodeDict.values()): if node.uId in duplicateDict: del self.nodeDict[node.uId] node.uId = uuid.uuid1().hex self.nodeDict[node.uId] = node def addNodesFromStruct(self, treeStruct, parent, position=-1): """Add nodes from the given structure under the given parent. Arguments: treeStruct -- the structure to insert parent -- the parent of the new nodes position -- the location to insert (-1 is appended) """ for nodeFormat in treeStruct.treeFormats.values(): self.treeFormats.addTypeIfMissing(nodeFormat) for node in treeStruct.nodeDict.values(): self.nodeDict[node.uId] = node node.formatRef = self.treeFormats[node.formatRef.name] for node in treeStruct.childList: if position >= 0: parent.childList.insert(position, node) position += 1 else: parent.childList.append(node) node.addSpotRef(parent) def debugCheck(self): """Run debugging checks on structure nodeDict, nodes and spots. Reports results to std output. Not to be run in production releases. """ print('\nChecking nodes in nodeDict:') nodeIds = set() errorCount = 0 for node in self.descendantGen(): nodeIds.add(node.uId) if node.uId not in self.nodeDict: print(' Node not in nodeDict, ID: {}, Title: {}'. format(node.uId, node.title())) errorCount += 1 for uId in set(self.nodeDict.keys()) - nodeIds: node = self.nodeDict[uId] print(' Node not in structure, ID: {}, Title: {}'. format(node.uId, node.title())) errorCount += 1 print(' {} errors found in nodeDict'.format(errorCount)) print('\nChecking spots:') errorCount = 0 for topNode in self.childList: for node in topNode.descendantGen(): for spot in node.spotRefs: if node not in spot.parentSpot.nodeRef.childList: print(' Invalid spot in node, ID: {}, Title: {}'. format(node.uId, node.title())) errorCount += 1 for child in node.childList: if len(child.spotRefs) < len(node.spotRefs): print(' Missing spot in node, ID: {}, Title: {}'. format(child.uId, child.title())) errorCount += 1 print(' {} errors found in spots'.format(errorCount)) #### Utility Functions #### def structFromMimeData(mimeData): """Return a tree structure based on mime data. Arguments: mimeData -- data to be used """ try: data = json.loads(str(mimeData.data('application/json'), 'utf-8')) return TreeStructure(data, addSpots=False) except (ValueError, KeyError, TypeError): return None TreeLine-3.2.1/source/treeview.py000066400000000000000000001000351506556630100167360ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treeview.py, provides a class for the indented tree view # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import unicodedata from PyQt6.QtCore import QEvent, QPoint, QPointF, Qt, pyqtSignal from PyQt6.QtGui import (QContextMenuEvent, QKeySequence, QMouseEvent, QTextDocument) from PyQt6.QtWidgets import (QAbstractItemView, QApplication, QHeaderView, QLabel, QListWidget, QListWidgetItem, QMenu, QStyledItemDelegate, QTreeView) import treeselection import treenode import miscdialogs import globalref class TreeView(QTreeView): """Class override for the indented tree view. Sets view defaults and links with document for content. """ skippedMouseSelect = pyqtSignal(treenode.TreeNode) shortcutEntered = pyqtSignal(QKeySequence) def __init__(self, model, allActions, parent=None): """Initialize the tree view. Arguments: model -- the initial model for view data allActions -- a dictionary of control actions for popup menus parent -- the parent main window """ super().__init__(parent) self.resetModel(model) self.allActions = allActions self.incremSearchMode = False self.incremSearchString = '' self.noMouseSelectMode = False self.mouseFocusNoEditMode = False self.prevSelSpot = None # temp, to check for edit at mouse release self.setSelectionMode(QAbstractItemView.SelectionMode. ExtendedSelection) self.header().setSectionResizeMode(0, QHeaderView.ResizeMode. ResizeToContents) self.header().setStretchLastSection(False) self.setHeaderHidden(True) self.setItemDelegate(TreeEditDelegate(self)) # use mouse event for editing to avoid with multiple select self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.updateTreeGenOptions() self.setDragDropMode(QAbstractItemView.DragDropMode.DragDrop) self.setDefaultDropAction(Qt.DropAction.MoveAction) self.setDropIndicatorShown(True) self.setUniformRowHeights(True) def resetModel(self, model): """Change the model assigned to this view. Also assigns a new selection model. Arguments: model -- the new model to assign """ self.setModel(model) self.setSelectionModel(treeselection.TreeSelection(model, self)) def updateTreeGenOptions(self): """Set the tree to match the current general options. """ dragAvail = globalref.genOptions['DragTree'] self.setDragEnabled(dragAvail) self.setAcceptDrops(dragAvail) self.setIndentation(globalref.genOptions['IndentOffset'] * self.fontInfo().pixelSize()) def isSpotExpanded(self, spot): """Return True if the given spot is expanded (showing children). Arguments: spot -- the spot to check """ return self.isExpanded(spot.index(self.model())) def expandSpot(self, spot): """Expand a spot in this view. Arguments: spot -- the spot to expand """ self.expand(spot.index(self.model())) def collapseSpot(self, spot): """Collapse a spot in this view. Arguments: spot -- the spot to collapse """ self.collapse(spot.index(self.model())) def expandBranch(self, parentSpot): """Expand all spots in the given branch. Collapses parentSpot first to avoid extreme slowness. Arguments: parentSpot -- the top spot in the branch """ self.collapse(parentSpot.index(self.model())) for spot in parentSpot.spotDescendantOnlyGen(): if spot.nodeRef.childList: self.expand(spot.index(self.model())) self.expand(parentSpot.index(self.model())) def collapseBranch(self, parentSpot): """Collapse all spots in the given branch. Arguments: parentSpot -- the top spot in the branch """ for spot in parentSpot.spotDescendantGen(): if spot.nodeRef.childList: self.collapse(spot.index(self.model())) def savedExpandState(self, spots): """Return a list of tuples of spots and expanded state (True/False). Arguments: spots -- an iterable of spots to save """ return [(spot, self.isSpotExpanded(spot)) for spot in spots] def restoreExpandState(self, expandState): """Expand or collapse based on saved tuples. Arguments: expandState -- a list of tuples of spots and expanded state """ for spot, expanded in expandState: try: if expanded: self.expandSpot(spot) else: self.collapseSpot(spot) except ValueError: pass def spotAtTop(self): """If view is scrolled, return the spot at the top of the view. If not scrolled, return None. """ if self.verticalScrollBar().value() > 0: return self.indexAt(QPoint(0, 0)).internalPointer() return None def scrollToSpot(self, spot): """Scroll the view to move the spot to the top position. Arguments: spot -- the spot to move to the top """ self.scrollTo(spot.index(self.model()), QAbstractItemView.ScrollHint.PositionAtTop) def scrollTo(self, index, hint=QAbstractItemView.ScrollHint.EnsureVisible): """Scroll the view to make node at index visible. Overriden to stop autoScroll from horizontally jumping when selecting nodes. Arguments: index -- the node to be made visible hint -- where the visible item should be """ horizPos = self.horizontalScrollBar().value() super().scrollTo(index, hint) self.horizontalScrollBar().setValue(horizPos) def endEditing(self): """Stop the editing of any item being renamed. """ delegate = self.itemDelegate() if delegate.editor: delegate.commitData.emit(delegate.editor) self.closePersistentEditor(self.selectionModel().currentIndex()) def incremSearchStart(self): """Start an incremental title search. """ self.incremSearchMode = True self.incremSearchString = '' globalref.mainControl.currentStatusBar().showMessage(_('Search for:')) def incremSearchRun(self): """Perform an incremental title search. """ msg = _('Search for: {0}').format(self.incremSearchString) globalref.mainControl.currentStatusBar().showMessage(msg) if (self.incremSearchString and not self.selectionModel().selectTitleMatch(self.incremSearchString, True, True)): msg = _('Search for: {0} (not found)').format(self. incremSearchString) globalref.mainControl.currentStatusBar().showMessage(msg) def incremSearchNext(self): """Go to the next match in an incremental title search. """ if self.incremSearchString: if self.selectionModel().selectTitleMatch(self.incremSearchString): msg = _('Next: {0}').format(self.incremSearchString) else: msg = _('Next: {0} (not found)').format(self. incremSearchString) globalref.mainControl.currentStatusBar().showMessage(msg) def incremSearchPrev(self): """Go to the previous match in an incremental title search. """ if self.incremSearchString: if self.selectionModel().selectTitleMatch(self.incremSearchString, False): msg = _('Next: {0}').format(self.incremSearchString) else: msg = _('Next: {0} (not found)').format(self. incremSearchString) globalref.mainControl.currentStatusBar().showMessage(msg) def incremSearchStop(self): """End an incremental title search. """ self.incremSearchMode = False self.incremSearchString = '' globalref.mainControl.currentStatusBar().clearMessage() def showTypeMenu(self, menu): """Show a popup menu for setting the item type. """ index = self.selectionModel().currentIndex() self.scrollTo(index) rect = self.visualRect(index) pt = self.mapToGlobal(QPoint(rect.center().x(), rect.bottom())) menu.popup(pt) def contextMenu(self): """Return the context menu, creating it if necessary. """ menu = QMenu(self) menu.addAction(self.allActions['EditCut']) menu.addAction(self.allActions['EditCopy']) menu.addAction(self.allActions['EditPaste']) menu.addAction(self.allActions['NodeRename']) menu.addSeparator() menu.addAction(self.allActions['NodeInsertBefore']) menu.addAction(self.allActions['NodeInsertAfter']) menu.addAction(self.allActions['NodeAddChild']) menu.addSeparator() menu.addAction(self.allActions['NodeDelete']) menu.addAction(self.allActions['NodeIndent']) menu.addAction(self.allActions['NodeUnindent']) menu.addSeparator() menu.addAction(self.allActions['NodeMoveUp']) menu.addAction(self.allActions['NodeMoveDown']) menu.addSeparator() menu.addMenu(self.allActions['DataNodeType'].parent()) menu.addSeparator() menu.addAction(self.allActions['ViewExpandBranch']) menu.addAction(self.allActions['ViewCollapseBranch']) return menu def contextMenuEvent(self, event): """Show popup context menu on mouse click or menu key. Arguments: event -- the context menu event """ if event.reason() == QContextMenuEvent.Reason.Mouse: clickedSpot = self.indexAt(event.pos()).internalPointer() if not clickedSpot: event.ignore() return if clickedSpot not in self.selectionModel().selectedSpots(): self.selectionModel().selectSpots([clickedSpot]) pos = event.globalPos() else: # shown for menu key or other reason selectList = self.selectionModel().selectedSpots() if not selectList: event.ignore() return currentSpot = self.selectionModel().currentSpot() if currentSpot in selectList: selectList.insert(0, currentSpot) position = None for spot in selectList: rect = self.visualRect(spot.index(self.model())) pt = QPoint(rect.center().x(), rect.bottom()) if self.rect().contains(pt): position = pt break if not position: self.scrollTo(selectList[0].index(self.model())) rect = self.visualRect(selectList[0].index(self.model())) position = QPoint(rect.center().x(), rect.bottom()) pos = self.mapToGlobal(position) self.contextMenu().popup(pos) event.accept() def dropEvent(self, event): """Event handler for view drop actions. Selects parent node at destination. Arguments: event -- the drop event """ clickedSpot = self.indexAt(event.position().toPoint()).internalPointer() # clear selection to avoid invalid multiple selection bug self.selectionModel().selectSpots([], False) if clickedSpot: super().dropEvent(event) self.selectionModel().selectSpots([clickedSpot], False) self.scheduleDelayedItemsLayout() # reqd before expand self.expandSpot(clickedSpot) else: super().dropEvent(event) self.selectionModel().selectSpots([]) self.scheduleDelayedItemsLayout() if event.isAccepted(): self.model().treeModified.emit(True, True) def toggleNoMouseSelectMode(self, active=True): """Set noMouseSelectMode to active or inactive. noMouseSelectMode will not change selection on mouse click, it will just signal the clicked node for use in links, etc. Arguments: active -- if True, activate noMouseSelectMode """ self.noMouseSelectMode = active def clearHover(self): """Post a mouse move event to clear the mouse hover indication. Needed to avoid crash when deleting nodes with hovered child nodes. """ event = QMouseEvent(QEvent.Type.MouseMove, QPointF(0.0, self.viewport().width()), Qt.MouseButton.NoButton, Qt.MouseButton.NoButton, Qt.KeyboardModifier.NoModifier) QApplication.postEvent(self.viewport(), event) QApplication.processEvents() def mousePressEvent(self, event): """Skip unselecting click if in noMouseSelectMode. If in noMouseSelectMode, signal which node is under the mouse. Arguments: event -- the mouse click event """ if self.incremSearchMode: self.incremSearchStop() self.prevSelSpot = None clickedIndex = self.indexAt(event.position().toPoint()) clickedSpot = clickedIndex.internalPointer() selectModel = self.selectionModel() if self.noMouseSelectMode: if clickedSpot and event.button() == Qt.MouseButton.LeftButton: self.skippedMouseSelect.emit(clickedSpot.nodeRef) event.ignore() return if (event.button() == Qt.MouseButton.LeftButton and not self.mouseFocusNoEditMode and selectModel.selectedCount() == 1 and selectModel.currentSpot() == selectModel.selectedSpots()[0] and event.position().x() > self.visualRect(clickedIndex).left() and globalref.genOptions['ClickRename']): # set for edit if single select and not an expand/collapse click self.prevSelSpot = selectModel.selectedSpots()[0] self.mouseFocusNoEditMode = False super().mousePressEvent(event) def mouseReleaseEvent(self, event): """Initiate editing if clicking on a single selected node. Arguments: event -- the mouse click event """ clickedIndex = self.indexAt(event.position().toPoint()) clickedSpot = clickedIndex.internalPointer() if (event.button() == Qt.MouseButton.LeftButton and self.prevSelSpot and clickedSpot == self.prevSelSpot): self.edit(clickedIndex) event.ignore() return self.prevSelSpot = None super().mouseReleaseEvent(event) def keyPressEvent(self, event): """Record characters if in incremental search mode. Arguments: event -- the key event """ if self.incremSearchMode: if event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter, Qt.Key.Key_Escape): self.incremSearchStop() elif event.key() == Qt.Key.Key_Backspace and self.incremSearchString: self.incremSearchString = self.incremSearchString[:-1] self.incremSearchRun() elif event.text() and unicodedata.category(event.text()) != 'Cc': # unicode category excludes control characters self.incremSearchString += event.text() self.incremSearchRun() event.accept() elif (event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter) and not self.itemDelegate().editor): # enter key selects current item if not selected selectModel = self.selectionModel() if selectModel.currentSpot() not in selectModel.selectedSpots(): selectModel.selectSpots([selectModel.currentSpot()]) event.accept() else: super().keyPressEvent(event) else: super().keyPressEvent(event) def focusInEvent(self, event): """Avoid editing a tree item with a get-focus click. Arguments: event -- the focus in event """ if event.reason() == Qt.FocusReason.MouseFocusReason: self.mouseFocusNoEditMode = True super().focusInEvent(event) def focusOutEvent(self, event): """Stop incremental search on focus loss. Arguments: event -- the focus out event """ if self.incremSearchMode: self.incremSearchStop() super().focusOutEvent(event) class TreeEditDelegate(QStyledItemDelegate): """Class override for editing tree items to capture shortcut keys. """ def __init__(self, parent=None): """Initialize the delegate class. Arguments: parent -- the parent view """ super().__init__(parent) self.editor = None def createEditor(self, parent, styleOption, modelIndex): """Return a new text editor for an item. Arguments: parent -- the parent widget for the editor styleOption -- the data for styles and geometry modelIndex -- the index of the item to be edited """ self.editor = super().createEditor(parent, styleOption, modelIndex) return self.editor def destroyEditor(self, editor, index): """Reset editor storage after editing ends. Arguments: editor -- the editor that is ending index -- the index of the edited item """ self.editor = None super().destroyEditor(editor, index) def eventFilter(self, editor, event): """Override to handle shortcut control keys. Arguments: editor -- the editor that Qt installed a filter on event -- the key press event """ if (event.type() == QEvent.Type.KeyPress and event.modifiers() == Qt.KeyboardModifier.ControlModifier and Qt.Key.Key_A <= event.key() <= Qt.Key.Key_Z): key = QKeySequence(event.keyCombination()) self.parent().shortcutEntered.emit(key) return True return super().eventFilter(editor, event) class TreeFilterViewItem(QListWidgetItem): """Item container for the flat list of filtered nodes. """ def __init__(self, spot, viewParent=None): """Initialize the list view item. Arguments: spot -- the spot to reference for content viewParent -- the parent list view """ super().__init__(viewParent) self.spot = spot self.setFlags(Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable | Qt.ItemFlag.ItemIsEnabled) self.update() def update(self): """Update title and icon from the stored node. """ node = self.spot.nodeRef self.setText(node.title()) if globalref.genOptions['ShowTreeIcons']: icon = globalref.treeIcons.getIcon(node.formatRef.iconName, True) if icon: self.setIcon(icon) class TreeFilterView(QListWidget): """View to show flat list of filtered nodes. """ skippedMouseSelect = pyqtSignal(treenode.TreeNode) shortcutEntered = pyqtSignal(QKeySequence) def __init__(self, treeViewRef, allActions, parent=None): """Initialize the list view. Arguments: treeViewRef -- a ref to the tree view for data allActions -- a dictionary of control actions for popup menus parent -- the parent main window """ super().__init__(parent) self.structure = treeViewRef.model().treeStructure self.selectionModel = treeViewRef.selectionModel() self.treeModel = treeViewRef.model() self.allActions = allActions self.menu = None self.noMouseSelectMode = False self.mouseFocusNoEditMode = False self.prevSelSpot = None # temp, to check for edit at mouse release self.drivingSelectionChange = False self.conditionalFilter = None self.messageLabel = None self.filterWhat = miscdialogs.FindScope.fullData self.filterHow = miscdialogs.FindType.keyWords self.filterStr = '' self.setSelectionMode(QAbstractItemView.SelectionMode. ExtendedSelection) self.setItemDelegate(TreeEditDelegate(self)) # use mouse event for editing to avoid with multiple select self.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.itemSelectionChanged.connect(self.updateSelectionModel) self.itemChanged.connect(self.changeTitle) treeFont = QTextDocument().defaultFont() treeFontName = globalref.miscOptions['TreeFont'] if treeFontName: treeFont.fromString(treeFontName) self.setFont(treeFont) def updateItem(self, node): """Update the item corresponding to the given node. Arguments: node -- the node to be updated """ for row in range(self.count()): if self.item(row).spot.nodeRef == node: self.blockSignals(True) self.item(row).update() self.blockSignals(False) return def updateContents(self): """Update filtered contents from current structure and filter criteria. """ if self.conditionalFilter: self.conditionalUpdate() return QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) if self.filterHow == miscdialogs.FindType.regExp: criteria = [re.compile(self.filterStr)] useRegExpFilter = True elif self.filterHow == miscdialogs.FindType.fullWords: criteria = [] for word in self.filterStr.lower().split(): criteria.append(re.compile(r'(?i)\b{}\b'. format(re.escape(word)))) useRegExpFilter = True elif self.filterHow == miscdialogs.FindType.keyWords: criteria = self.filterStr.lower().split() useRegExpFilter = False else: # full phrase criteria = [self.filterStr.lower().strip()] useRegExpFilter = False titlesOnly = self.filterWhat == miscdialogs.FindScope.titlesOnly self.blockSignals(True) self.clear() if useRegExpFilter: for rootSpot in self.structure.rootSpots(): for spot in rootSpot.spotDescendantGen(): if spot.nodeRef.regExpSearch(criteria, titlesOnly): item = TreeFilterViewItem(spot, self) else: for rootSpot in self.structure.rootSpots(): for spot in rootSpot.spotDescendantGen(): if spot.nodeRef.wordSearch(criteria, titlesOnly): item = TreeFilterViewItem(spot, self) self.blockSignals(False) self.selectItems(self.selectionModel.selectedSpots(), True) if self.count() and not self.selectedItems(): self.item(0).setSelected(True) if not self.messageLabel: self.messageLabel = QLabel() globalref.mainControl.currentStatusBar().addWidget(self. messageLabel) message = _('Filtering by "{0}", found {1} nodes').format(self. filterStr, self.count()) self.messageLabel.setText(message) QApplication.restoreOverrideCursor() def conditionalUpdate(self): """Update filtered contents from structure and conditional criteria. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) self.blockSignals(True) self.clear() for rootSpot in self.structure.rootSpots(): for spot in rootSpot.spotDescendantGen(): if self.conditionalFilter.evaluate(spot.nodeRef): item = TreeFilterViewItem(spot, self) self.blockSignals(False) self.selectItems(self.selectionModel.selectedSpots(), True) if self.count() and not self.selectedItems(): self.item(0).setSelected(True) if not self.messageLabel: self.messageLabel = QLabel() globalref.mainControl.currentStatusBar().addWidget(self. messageLabel) message = _('Conditional filtering, found {0} nodes').format(self. count()) self.messageLabel.setText(message) QApplication.restoreOverrideCursor() def selectItems(self, spots, signalModel=False): """Select items matching given nodes if in filtered view. Arguments: spots -- the spot list to select signalModel -- signal to update the tree selection model if True """ selectSpots = set(spots) if not signalModel: self.blockSignals(True) for item in self.selectedItems(): item.setSelected(False) for row in range(self.count()): if self.item(row).spot in selectSpots: self.item(row).setSelected(True) self.setCurrentItem(self.item(row)) self.blockSignals(False) def updateFromSelectionModel(self): """Select items selected in the tree selection model. Called from a signal that the tree selection model is changing. """ if self.count() and not self.drivingSelectionChange: self.selectItems(self.selectionModel.selectedSpots()) def updateSelectionModel(self): """Change the selection model based on a filter list selection signal. """ self.drivingSelectionChange = True self.selectionModel.selectSpots([item.spot for item in self.selectedItems()]) self.drivingSelectionChange = False def changeTitle(self, item): """Update the node title in the model based on an edit signal. Reset to the node text if invalid. Arguments: item -- the filter view item that changed """ if not self.treeModel.setData(item.spot.index(self.treeModel), item.text()): self.blockSignals(True) item.setText(item.node.title()) self.blockSignals(False) def nextPrevSpot(self, spot, forward=True): """Return the next or previous spot in this filter list view. Wraps around ends. Return None if view doesn't have spot. Arguments: spot -- the starting spot forward -- next if True, previous if False """ for row in range(self.count()): if self.item(row).spot == spot: if forward: row += 1 if row >= self.count(): row = 0 else: row -= 1 if row < 0: row = self.count() - 1 return self.item(row).spot return None def contextMenu(self): """Return the context menu, creating it if necessary. """ if not self.menu: self.menu = QMenu(self) self.menu.addAction(self.allActions['EditCut']) self.menu.addAction(self.allActions['EditCopy']) self.menu.addAction(self.allActions['NodeRename']) self.menu.addSeparator() self.menu.addAction(self.allActions['NodeDelete']) self.menu.addSeparator() self.menu.addMenu(self.allActions['DataNodeType'].parent()) return self.menu def contextMenuEvent(self, event): """Show popup context menu on mouse click or menu key. Arguments: event -- the context menu event """ if event.reason() == QContextMenuEvent.Reason.Mouse: clickedItem = self.itemAt(event.pos()) if not clickedItem: event.ignore() return if clickedItem.spot not in self.selectionModel.selectedSpots(): self.selectionModel.selectSpots([clickedItem.spot]) pos = event.globalPos() else: # shown for menu key or other reason selectList = self.selectedItems() if not selectList: event.ignore() return currentItem = self.currentItem() if currentItem in selectList: selectList.insert(0, currentItem) posList = [] for item in selectList: rect = self.visualItemRect(item) pt = QPoint(rect.center().x(), rect.bottom()) if self.rect().contains(pt): posList.append(pt) if not posList: self.scrollTo(self.indexFromItem(selectList[0])) rect = self.visualItemRect(selectList[0]) posList = [QPoint(rect.center().x(), rect.bottom())] pos = self.mapToGlobal(posList[0]) self.contextMenu().popup(pos) event.accept() def toggleNoMouseSelectMode(self, active=True): """Set noMouseSelectMode to active or inactive. noMouseSelectMode will not change selection on mouse click, it will just signal the clicked node for use in links, etc. Arguments: active -- if True, activate noMouseSelectMode """ self.noMouseSelectMode = active def mousePressEvent(self, event): """Skip unselecting click on blank spaces. Arguments: event -- the mouse click event """ self.prevSelSpot = None clickedItem = self.itemAt(event.position().toPoint()) if not clickedItem: event.ignore() return if self.noMouseSelectMode: if event.button() == Qt.MouseButton.LeftButton: self.skippedMouseSelect.emit(clickedItem.spot.nodeRef) event.ignore() return if (event.button() == Qt.MouseButton.LeftButton and not self.mouseFocusNoEditMode and self.selectionModel.selectedCount() == 1 and globalref.genOptions['ClickRename']): self.prevSelSpot = self.selectionModel.selectedSpots()[0] self.mouseFocusNoEditMode = False super().mousePressEvent(event) def mouseReleaseEvent(self, event): """Initiate editing if clicking on a single selected node. Arguments: event -- the mouse click event """ clickedItem = self.itemAt(event.position().toPoint()) if (event.button() == Qt.MouseButton.LeftButton and clickedItem and self.prevSelSpot and clickedItem.spot == self.prevSelSpot): self.editItem(clickedItem) event.ignore() return self.prevSelSpot = None super().mouseReleaseEvent(event) def focusInEvent(self, event): """Avoid editing a tree item with a get-focus click. Arguments: event -- the focus in event """ if event.reason() == Qt.FocusReason.MouseFocusReason: self.mouseFocusNoEditMode = True super().focusInEvent(event) TreeLine-3.2.1/source/treewindow.py000066400000000000000000001213521506556630100173000ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # treewindow.py, provides a class for the main window and controls # # TreeLine, an information storage program # Copyright (C) 2025, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import pathlib import base64 from PyQt6.QtCore import QEvent, QRect, QSize, Qt, pyqtSignal from PyQt6.QtGui import QAction, QActionGroup, QGuiApplication, QTextDocument from PyQt6.QtWidgets import (QApplication, QMainWindow, QSplitter, QStackedWidget, QStatusBar, QTabWidget) import treeview import breadcrumbview import outputview import dataeditview import titlelistview import treenode import globalref class TreeWindow(QMainWindow): """Class override for the main window. Contains main window views and controls. """ selectChanged = pyqtSignal() nodeModified = pyqtSignal(treenode.TreeNode) treeModified = pyqtSignal() winActivated = pyqtSignal(QMainWindow) winMinimized = pyqtSignal() winClosing = pyqtSignal(QMainWindow) def __init__(self, model, allActions, parent=None): """Initialize the main window. Arguments: model -- the initial data model allActions -- a dict containing the upper level actions parent -- the parent window, usually None """ super().__init__(parent) self.allActions = allActions.copy() self.allowCloseFlag = True self.winActions = {} self.toolbars = [] self.rightTabActList = [] self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose) self.setAcceptDrops(True) self.setStatusBar(QStatusBar()) self.setCaption() self.setupActions() self.setupMenus() self.setupToolbars() self.restoreToolbarPosition() self.treeView = treeview.TreeView(model, self.allActions) self.breadcrumbSplitter = QSplitter(Qt.Orientation.Vertical) self.setCentralWidget(self.breadcrumbSplitter) self.breadcrumbView = breadcrumbview.BreadcrumbView(self.treeView) self.breadcrumbSplitter.addWidget(self.breadcrumbView) self.breadcrumbView.setVisible(globalref. genOptions['InitShowBreadcrumb']) self.treeSplitter = QSplitter() self.breadcrumbSplitter.addWidget(self.treeSplitter) self.treeStack = QStackedWidget() self.treeSplitter.addWidget(self.treeStack) self.treeStack.addWidget(self.treeView) self.treeView.shortcutEntered.connect(self.execShortcut) self.treeView.selectionModel().selectionChanged.connect(self. updateRightViews) self.treeFilterView = None self.rightTabs = QTabWidget() self.treeSplitter.addWidget(self.rightTabs) self.rightTabs.setTabPosition(QTabWidget.TabPosition.South) self.rightTabs.tabBar().setFocusPolicy(Qt.FocusPolicy.NoFocus) self.outputSplitter = QSplitter(Qt.Orientation.Vertical) self.rightTabs.addTab(self.outputSplitter, _('Data Output')) parentOutputView = outputview.OutputView(self.treeView, False) parentOutputView.highlighted.connect(self.setStatusFromUrl) self.outputSplitter.addWidget(parentOutputView) childOutputView = outputview.OutputView(self.treeView, True) childOutputView.highlighted.connect(self.setStatusFromUrl) self.outputSplitter.addWidget(childOutputView) self.editorSplitter = QSplitter(Qt.Orientation.Vertical) self.rightTabs.addTab(self.editorSplitter, _('Data Edit')) parentEditView = dataeditview.DataEditView(self.treeView, self.allActions, False) parentEditView.shortcutEntered.connect(self.execShortcut) parentEditView.focusOtherView.connect(self.focusNextView) parentEditView.inLinkSelectMode.connect(self.treeView. toggleNoMouseSelectMode) self.treeView.skippedMouseSelect.connect(parentEditView. internalLinkSelected) self.editorSplitter.addWidget(parentEditView) childEditView = dataeditview.DataEditView(self.treeView, self.allActions, True) childEditView.shortcutEntered.connect(self.execShortcut) childEditView.focusOtherView.connect(self.focusNextView) childEditView.inLinkSelectMode.connect(self.treeView. toggleNoMouseSelectMode) self.treeView.skippedMouseSelect.connect(childEditView. internalLinkSelected) parentEditView.hoverFocusActive.connect(childEditView.endEditor) childEditView.hoverFocusActive.connect(parentEditView.endEditor) parentEditView.inLinkSelectMode.connect(childEditView. updateInLinkSelectMode) childEditView.inLinkSelectMode.connect(parentEditView. updateInLinkSelectMode) self.editorSplitter.addWidget(childEditView) self.titleSplitter = QSplitter(Qt.Orientation.Vertical) self.rightTabs.addTab(self.titleSplitter, _('Title List')) parentTitleView = titlelistview.TitleListView(self.treeView, False) parentTitleView.shortcutEntered.connect(self.execShortcut) self.titleSplitter.addWidget(parentTitleView) childTitleView = titlelistview.TitleListView(self.treeView, True) childTitleView.shortcutEntered.connect(self.execShortcut) self.titleSplitter.addWidget(childTitleView) self.rightTabs.currentChanged.connect(self.updateRightViews) self.updateFonts() def setExternalSignals(self): """Connect widow object signals to signals in this object. In a separate method to refresh after local control change. """ self.treeView.selectionModel().selectionChanged.connect(self. selectChanged) for i in range(2): self.editorSplitter.widget(i).nodeModified.connect(self. nodeModified) self.titleSplitter.widget(i).nodeModified.connect(self. nodeModified) self.titleSplitter.widget(i).treeModified.connect(self. treeModified) def updateActions(self, allActions): """Use new actions for menus, etc. when the local control changes. Arguments: allActions -- a dict containing the upper level actions """ # remove submenu actions that are children of the window self.removeAction(self.allActions['DataNodeType']) self.removeAction(self.allActions['FormatFontSize']) self.allActions = allActions.copy() self.allActions.update(self.winActions) self.menuBar().clear() self.setupMenus() self.addToolbarCommands() self.treeView.allActions = self.allActions for i in range(2): self.editorSplitter.widget(i).allActions = self.allActions def updateTreeNode(self, node): """Update all spots for the given node in the tree view. Arguments: node -- the node to be updated """ for spot in node.spotRefs: self.treeView.update(spot.index(self.treeView.model())) self.treeView.resizeColumnToContents(0) self.breadcrumbView.updateContents() def updateTree(self): """Update the full tree view. """ self.treeView.scheduleDelayedItemsLayout() self.breadcrumbView.updateContents() def updateRightViews(self, *args, outputOnly=False): """Update all right-hand views and breadcrumb view. Arguments: *args -- dummy arguments to collect args from signals outputOnly -- only update output views (not edit views) """ if globalref.mainControl.activeControl: self.rightTabActList[self.rightTabs. currentIndex()].setChecked(True) self.breadcrumbView.updateContents() splitter = self.rightTabs.currentWidget() if not outputOnly or isinstance(splitter.widget(0), outputview.OutputView): for i in range(2): splitter.widget(i).updateContents() def refreshDataEditViews(self): """Refresh the data in non-selected cells in curreent data edit views. """ splitter = self.rightTabs.currentWidget() if isinstance(splitter.widget(0), dataeditview.DataEditView): for i in range(2): splitter.widget(i).updateUnselectedCells() def updateCommandsAvail(self): """Set window commands available based on node selections. """ self.allActions['ViewPrevSelect'].setEnabled(len(self.treeView. selectionModel(). prevSpots) > 1) self.allActions['ViewNextSelect'].setEnabled(len(self.treeView. selectionModel(). nextSpots) > 0) def updateWinGenOptions(self): """Update tree and data edit windows based on general option changes. """ self.treeView.updateTreeGenOptions() for i in range(2): self.editorSplitter.widget(i).setMouseTracking(globalref. genOptions['EditorOnHover']) def updateFonts(self): """Update custom fonts in views. """ treeFont = QTextDocument().defaultFont() treeFontName = globalref.miscOptions['TreeFont'] if treeFontName: treeFont.fromString(treeFontName) self.treeView.setFont(treeFont) self.treeView.updateTreeGenOptions() if self.treeFilterView: self.treeFilterView.setFont(treeFont) ouputFont = QTextDocument().defaultFont() ouputFontName = globalref.miscOptions['OutputFont'] if ouputFontName: ouputFont.fromString(ouputFontName) editorFont = QTextDocument().defaultFont() editorFontName = globalref.miscOptions['EditorFont'] if editorFontName: editorFont.fromString(editorFontName) for i in range(2): self.outputSplitter.widget(i).setFont(ouputFont) self.editorSplitter.widget(i).setFont(editorFont) self.titleSplitter.widget(i).setFont(editorFont) def resetTreeModel(self, model): """Change the model assigned to the tree view. Arguments: model -- the new model to assign """ self.treeView.resetModel(model) self.treeView.selectionModel().selectionChanged.connect(self. updateRightViews) def activateAndRaise(self): """Activate this window and raise it to the front. """ self.activateWindow() self.raise_() def setCaption(self, pathObj=None, modified=False): """Change the window caption title based on the file name and path. Arguments: pathObj - a path object for the current file """ modFlag = '*' if modified else '' if pathObj: caption = '{0}{1} [{2}] - TreeLine'.format(str(pathObj.name), modFlag, str(pathObj.parent)) else: caption = '- TreeLine' self.setWindowTitle(caption) def setStatusFromUrl(self, url): """Set the status bar message to the text from a hovered-over URL. Arguments: url - the QUrl to show """ self.statusBar().showMessage(url.toString()) def filterView(self): """Create, show and return a filter view. """ self.removeFilterView() self.treeFilterView = treeview.TreeFilterView(self.treeView, self.allActions) self.treeFilterView.shortcutEntered.connect(self.execShortcut) self.treeView.selectionModel().selectionChanged.connect(self. treeFilterView. updateFromSelectionModel) for i in range(2): editView = self.editorSplitter.widget(i) editView.inLinkSelectMode.connect(self.treeFilterView. toggleNoMouseSelectMode) self.treeFilterView.skippedMouseSelect.connect(editView. internalLinkSelected) self.treeStack.addWidget(self.treeFilterView) self.treeStack.setCurrentWidget(self.treeFilterView) return self.treeFilterView def removeFilterView(self): """Hide and delete the current filter view. """ if self.treeFilterView != None: # check for None since False if empty self.treeStack.removeWidget(self.treeFilterView) globalref.mainControl.currentStatusBar().removeWidget(self. treeFilterView. messageLabel) self.treeFilterView.messageLabel.deleteLater() self.treeFilterView = None def rightParentView(self): """Return the current right-hand parent view if visible (or None). """ view = self.rightTabs.currentWidget().widget(0) if not view.isVisible() or view.height() == 0 or view.width() == 0: return None return view def rightChildView(self): """Return the current right-hand parent view if visible (or None). """ view = self.rightTabs.currentWidget().widget(1) if not view.isVisible() or view.height() == 0 or view.width() == 0: return None return view def focusNextView(self, forward=True): """Focus the next pane in the tab focus series. Called by a signal from the data edit views. Tab sequences tend to skip views without this. Arguments: forward -- forward in tab series if True """ reason = (Qt.FocusReason.TabFocusReason if forward else Qt.FocusReason.BacktabFocusReason) rightParent = self.rightParentView() rightChild = self.rightChildView() if (self.sender().isChildView == forward or (forward and rightChild == None) or (not forward and rightParent == None)): self.treeView.setFocus(reason) elif forward: rightChild.setFocus(reason) else: rightParent.setFocus(reason) def execShortcut(self, key): """Execute an action based on a shortcut key signal from a view. Arguments: key -- the QKeySequence shortcut """ keyDict = {action.shortcut().toString(): action for action in self.allActions.values()} try: action = keyDict[key.toString()] except KeyError: return if action.isEnabled(): action.trigger() def setupActions(self): """Add the actions for contols at the window level. These actions only affect an individual window, they're independent in multiple windows of the same file. """ viewExpandBranchAct = QAction(_('&Expand Full Branch'), self, statusTip=_('Expand all children of the selected nodes')) viewExpandBranchAct.triggered.connect(self.viewExpandBranch) self.winActions['ViewExpandBranch'] = viewExpandBranchAct viewCollapseBranchAct = QAction(_('&Collapse Full Branch'), self, statusTip=_('Collapse all children of the selected nodes')) viewCollapseBranchAct.triggered.connect(self.viewCollapseBranch) self.winActions['ViewCollapseBranch'] = viewCollapseBranchAct viewPrevSelectAct = QAction(_('&Previous Selection'), self, statusTip=_('Return to the previous tree selection')) viewPrevSelectAct.triggered.connect(self.viewPrevSelect) self.winActions['ViewPrevSelect'] = viewPrevSelectAct viewNextSelectAct = QAction(_('&Next Selection'), self, statusTip=_('Go to the next tree selection in history')) viewNextSelectAct.triggered.connect(self.viewNextSelect) self.winActions['ViewNextSelect'] = viewNextSelectAct viewRightTabGrp = QActionGroup(self) viewOutputAct = QAction(_('Show Data &Output'), viewRightTabGrp, statusTip=_('Show data output in right view'), checkable=True) self.winActions['ViewDataOutput'] = viewOutputAct viewEditAct = QAction(_('Show Data &Editor'), viewRightTabGrp, statusTip=_('Show data editor in right view'), checkable=True) self.winActions['ViewDataEditor'] = viewEditAct viewTitleAct = QAction(_('Show &Title List'), viewRightTabGrp, statusTip=_('Show title list in right view'), checkable=True) self.winActions['ViewTitleList'] = viewTitleAct self.rightTabActList = [viewOutputAct, viewEditAct, viewTitleAct] viewRightTabGrp.triggered.connect(self.viewRightTab) viewBreadcrumbAct = QAction(_('Show &Breadcrumb View'), self, statusTip=_('Toggle showing breadcrumb ancestor view'), checkable=True) viewBreadcrumbAct.setChecked(globalref. genOptions['InitShowBreadcrumb']) viewBreadcrumbAct.triggered.connect(self.viewBreadcrumb) self.winActions['ViewBreadcrumb'] = viewBreadcrumbAct viewChildPaneAct = QAction(_('&Show Child Pane'), self, statusTip=_('Toggle showing right-hand child views'), checkable=True) viewChildPaneAct.setChecked(globalref.genOptions['InitShowChildPane']) viewChildPaneAct.triggered.connect(self.viewShowChildPane) self.winActions['ViewShowChildPane'] = viewChildPaneAct viewDescendAct = QAction(_('Show Output &Descendants'), self, statusTip=_('Toggle showing output view indented descendants'), checkable=True) viewDescendAct.setChecked(globalref.genOptions['InitShowDescendants']) viewDescendAct.triggered.connect(self.viewDescendants) self.winActions['ViewShowDescend'] = viewDescendAct winCloseAct = QAction(_('&Close Window'), self, statusTip=_('Close this window')) winCloseAct.triggered.connect(self.close) self.winActions['WinCloseWindow'] = winCloseAct incremSearchStartAct = QAction(_('Start Incremental Search'), self) incremSearchStartAct.triggered.connect(self.incremSearchStart) self.addAction(incremSearchStartAct) self.winActions['IncremSearchStart'] = incremSearchStartAct incremSearchNextAct = QAction(_('Next Incremental Search'), self) incremSearchNextAct.triggered.connect(self.incremSearchNext) self.addAction(incremSearchNextAct) self.winActions['IncremSearchNext'] = incremSearchNextAct incremSearchPrevAct = QAction(_('Previous Incremental Search'), self) incremSearchPrevAct.triggered.connect(self.incremSearchPrev) self.addAction(incremSearchPrevAct) self.winActions['IncremSearchPrev'] = incremSearchPrevAct for name, action in self.winActions.items(): icon = globalref.toolIcons.getIcon(name.lower()) if icon: action.setIcon(icon) key = globalref.keyboardOptions[name] if not key.isEmpty(): action.setShortcut(key) self.allActions.update(self.winActions) def setupToolbars(self): """Add toolbars based on option settings. """ for toolbar in self.toolbars: self.removeToolBar(toolbar) self.toolbars = [] numToolbars = globalref.toolbarOptions['ToolbarQuantity'] iconSize = globalref.toolbarOptions['ToolbarSize'] for num in range(numToolbars): name = 'Toolbar{:d}'.format(num) toolbar = self.addToolBar(name) toolbar.setObjectName(name) toolbar.setIconSize(QSize(iconSize, iconSize)) self.toolbars.append(toolbar) self.addToolbarCommands() def addToolbarCommands(self): """Add toolbar commands for current actions. """ for toolbar, commandList in zip(self.toolbars, globalref. toolbarOptions['ToolbarCommands']): toolbar.clear() for command in commandList.split(','): if command: try: toolbar.addAction(self.allActions[command]) except KeyError: pass else: toolbar.addSeparator() def setupMenus(self): """Add menu items for actions. """ self.fileMenu = self.menuBar().addMenu(_('&File')) self.fileMenu.aboutToShow.connect(self.loadRecentMenu) self.fileMenu.addAction(self.allActions['FileNew']) self.fileMenu.addAction(self.allActions['FileOpen']) self.fileMenu.addAction(self.allActions['FileOpenSample']) self.fileMenu.addAction(self.allActions['FileImport']) self.fileMenu.addSeparator() self.fileMenu.addAction(self.allActions['FileSave']) self.fileMenu.addAction(self.allActions['FileSaveAs']) self.fileMenu.addAction(self.allActions['FileExport']) self.fileMenu.addAction(self.allActions['FileProperties']) self.fileMenu.addSeparator() self.fileMenu.addAction(self.allActions['FilePrintSetup']) self.fileMenu.addAction(self.allActions['FilePrintPreview']) self.fileMenu.addAction(self.allActions['FilePrint']) self.fileMenu.addAction(self.allActions['FilePrintPdf']) self.fileMenu.addSeparator() self.recentFileSep = self.fileMenu.addSeparator() self.fileMenu.addAction(self.allActions['FileQuit']) editMenu = self.menuBar().addMenu(_('&Edit')) editMenu.addAction(self.allActions['EditUndo']) editMenu.addAction(self.allActions['EditRedo']) editMenu.addSeparator() editMenu.addAction(self.allActions['EditCut']) editMenu.addAction(self.allActions['EditCopy']) editMenu.addSeparator() editMenu.addAction(self.allActions['EditPaste']) editMenu.addAction(self.allActions['EditPastePlain']) editMenu.addSeparator() editMenu.addAction(self.allActions['EditPasteChild']) editMenu.addAction(self.allActions['EditPasteBefore']) editMenu.addAction(self.allActions['EditPasteAfter']) editMenu.addSeparator() editMenu.addAction(self.allActions['EditPasteCloneChild']) editMenu.addAction(self.allActions['EditPasteCloneBefore']) editMenu.addAction(self.allActions['EditPasteCloneAfter']) nodeMenu = self.menuBar().addMenu(_('&Node')) nodeMenu.addAction(self.allActions['NodeRename']) nodeMenu.addSeparator() nodeMenu.addAction(self.allActions['NodeAddChild']) nodeMenu.addAction(self.allActions['NodeInsertBefore']) nodeMenu.addAction(self.allActions['NodeInsertAfter']) nodeMenu.addSeparator() nodeMenu.addAction(self.allActions['NodeDelete']) nodeMenu.addAction(self.allActions['NodeIndent']) nodeMenu.addAction(self.allActions['NodeUnindent']) nodeMenu.addSeparator() nodeMenu.addAction(self.allActions['NodeMoveUp']) nodeMenu.addAction(self.allActions['NodeMoveDown']) nodeMenu.addAction(self.allActions['NodeMoveFirst']) nodeMenu.addAction(self.allActions['NodeMoveLast']) dataMenu = self.menuBar().addMenu(_('&Data')) # add action's parent to get the sub-menu dataMenu.addMenu(self.allActions['DataNodeType'].parent()) # add the action to activate the shortcut key self.addAction(self.allActions['DataNodeType']) dataMenu.addAction(self.allActions['DataConfigType']) dataMenu.addAction(self.allActions['DataCopyType']) dataMenu.addAction(self.allActions['DataVisualConfig']) dataMenu.addSeparator() dataMenu.addAction(self.allActions['DataSortNodes']) dataMenu.addAction(self.allActions['DataNumbering']) dataMenu.addAction(self.allActions['DataRegenRefs']) dataMenu.addSeparator() dataMenu.addAction(self.allActions['DataCloneMatches']) dataMenu.addAction(self.allActions['DataDetachClones']) dataMenu.addSeparator() dataMenu.addAction(self.allActions['DataFlatCategory']) dataMenu.addAction(self.allActions['DataAddCategory']) dataMenu.addAction(self.allActions['DataSwapCategory']) toolsMenu = self.menuBar().addMenu(_('&Tools')) toolsMenu.addAction(self.allActions['ToolsFindText']) toolsMenu.addAction(self.allActions['ToolsFindCondition']) toolsMenu.addAction(self.allActions['ToolsFindReplace']) toolsMenu.addSeparator() toolsMenu.addAction(self.allActions['ToolsFilterText']) toolsMenu.addAction(self.allActions['ToolsFilterCondition']) toolsMenu.addSeparator() toolsMenu.addAction(self.allActions['ToolsSpellCheck']) toolsMenu.addSeparator() toolsMenu.addAction(self.allActions['ToolsGenOptions']) toolsMenu.addSeparator() toolsMenu.addAction(self.allActions['ToolsShortcuts']) toolsMenu.addAction(self.allActions['ToolsToolbars']) toolsMenu.addAction(self.allActions['ToolsFonts']) toolsMenu.addAction(self.allActions['ToolsColors']) formatMenu = self.menuBar().addMenu(_('Fo&rmat')) formatMenu.addAction(self.allActions['FormatBoldFont']) formatMenu.addAction(self.allActions['FormatItalicFont']) formatMenu.addAction(self.allActions['FormatUnderlineFont']) formatMenu.addAction(self.allActions['FormatStrikethroughFont']) formatMenu.addSeparator() # add action's parent to get the sub-menu formatMenu.addMenu(self.allActions['FormatFontSize'].parent()) # add the action to activate the shortcut key self.addAction(self.allActions['FormatFontSize']) formatMenu.addAction(self.allActions['FormatFontColor']) formatMenu.addSeparator() formatMenu.addAction(self.allActions['FormatExtLink']) formatMenu.addAction(self.allActions['FormatIntLink']) formatMenu.addAction(self.allActions['FormatInsertDate']) formatMenu.addSeparator() formatMenu.addAction(self.allActions['FormatSelectAll']) formatMenu.addAction(self.allActions['FormatClearFormat']) viewMenu = self.menuBar().addMenu(_('&View')) viewMenu.addAction(self.allActions['ViewExpandBranch']) viewMenu.addAction(self.allActions['ViewCollapseBranch']) viewMenu.addSeparator() viewMenu.addAction(self.allActions['ViewPrevSelect']) viewMenu.addAction(self.allActions['ViewNextSelect']) viewMenu.addSeparator() viewMenu.addAction(self.allActions['ViewDataOutput']) viewMenu.addAction(self.allActions['ViewDataEditor']) viewMenu.addAction(self.allActions['ViewTitleList']) viewMenu.addSeparator() viewMenu.addAction(self.allActions['ViewBreadcrumb']) viewMenu.addAction(self.allActions['ViewShowChildPane']) viewMenu.addAction(self.allActions['ViewShowDescend']) self.windowMenu = self.menuBar().addMenu(_('&Window')) self.windowMenu.aboutToShow.connect(self.loadWindowMenu) self.windowMenu.addAction(self.allActions['WinNewWindow']) self.windowMenu.addAction(self.allActions['WinCloseWindow']) self.windowMenu.addSeparator() helpMenu = self.menuBar().addMenu(_('&Help')) helpMenu.addAction(self.allActions['HelpBasic']) helpMenu.addAction(self.allActions['HelpFull']) helpMenu.addSeparator() helpMenu.addAction(self.allActions['HelpAbout']) def viewExpandBranch(self): """Expand all children of the selected spots. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) selectedSpots = self.treeView.selectionModel().selectedSpots() if not selectedSpots: selectedSpots = self.treeView.model().treeStructure.rootSpots() for spot in selectedSpots: self.treeView.expandBranch(spot) QApplication.restoreOverrideCursor() def viewCollapseBranch(self): """Collapse all children of the selected spots. """ QApplication.setOverrideCursor(Qt.CursorShape.WaitCursor) selectedSpots = self.treeView.selectionModel().selectedSpots() if not selectedSpots: selectedSpots = self.treeView.model().treeStructure.rootSpots() for spot in selectedSpots: self.treeView.collapseBranch(spot) QApplication.restoreOverrideCursor() def viewPrevSelect(self): """Return to the previous tree selection. """ self.treeView.selectionModel().restorePrevSelect() def viewNextSelect(self): """Go to the next tree selection in history. """ self.treeView.selectionModel().restoreNextSelect() def viewRightTab(self, action): """Show the tab in the right-hand view given by action. Arguments: action -- the action triggered in the action group """ if action == self.allActions['ViewDataOutput']: self.rightTabs.setCurrentWidget(self.outputSplitter) elif action == self.allActions['ViewDataEditor']: self.rightTabs.setCurrentWidget(self.editorSplitter) else: self.rightTabs.setCurrentWidget(self.titleSplitter) def viewBreadcrumb(self, checked): """Enable or disable the display of the breadcrumb view. Arguments: checked -- True if to be shown, False if to be hidden """ self.breadcrumbView.setVisible(checked) if checked: self.updateRightViews() def viewShowChildPane(self, checked): """Enable or disable the display of children in a split pane. Arguments: checked -- True if to be shown, False if to be hidden """ for tabNum in range(3): for splitNum in range(2): view = self.rightTabs.widget(tabNum).widget(splitNum) view.hideChildView = not checked self.updateRightViews() def viewDescendants(self, checked): """Set the output view to show indented descendants if checked. Arguments: checked -- True if to be shown, False if to be hidden """ self.outputSplitter.widget(1).showDescendants = checked self.updateRightViews() def incremSearchStart(self): """Start an incremental title search. """ if not self.treeFilterView: self.treeView.setFocus() self.treeView.incremSearchStart() def incremSearchNext(self): """Go to the next match in an incremental title search. """ if not self.treeFilterView: self.treeView.incremSearchNext() def incremSearchPrev(self): """Go to the previous match in an incremental title search. """ if not self.treeFilterView: self.treeView.incremSearchPrev() def loadRecentMenu(self): """Load recent file items to file menu before showing. """ for action in self.fileMenu.actions(): text = action.text() if len(text) > 1 and text[0] == '&' and '0' <= text[1] <= '9': self.fileMenu.removeAction(action) self.fileMenu.insertActions(self.recentFileSep, globalref.mainControl.recentFiles. getActions()) def loadWindowMenu(self): """Load window list items to window menu before showing. """ for action in self.windowMenu.actions(): text = action.text() if len(text) > 1 and text[0] == '&' and '0' <= text[1] <= '9': self.windowMenu.removeAction(action) self.windowMenu.addActions(globalref.mainControl.windowActions()) def saveWindowGeom(self): """Save window geometry parameters to history options. """ contentsRect = self.geometry() frameRect = self.frameGeometry() globalref.histOptions.changeValue('WindowXSize', contentsRect.width()) globalref.histOptions.changeValue('WindowYSize', contentsRect.height()) globalref.histOptions.changeValue('WindowXPos', contentsRect.x()) globalref.histOptions.changeValue('WindowYPos', contentsRect.y()) globalref.histOptions.changeValue('WindowTopMargin', contentsRect.y() - frameRect.y()) globalref.histOptions.changeValue('WindowOtherMargin', contentsRect.x() - frameRect.x()) try: upperWidth, lowerWidth = self.breadcrumbSplitter.sizes() crumbPercent = int(100 * upperWidth / (upperWidth + lowerWidth)) globalref.histOptions.changeValue('CrumbSplitPercent', crumbPercent) leftWidth, rightWidth = self.treeSplitter.sizes() treePercent = int(100 * leftWidth / (leftWidth + rightWidth)) globalref.histOptions.changeValue('TreeSplitPercent', treePercent) upperWidth, lowerWidth = self.outputSplitter.sizes() outputPercent = int(100 * upperWidth / (upperWidth + lowerWidth)) globalref.histOptions.changeValue('OutputSplitPercent', outputPercent) upperWidth, lowerWidth = self.editorSplitter.sizes() editorPercent = int(100 * upperWidth / (upperWidth + lowerWidth)) globalref.histOptions.changeValue('EditorSplitPercent', editorPercent) upperWidth, lowerWidth = self.titleSplitter.sizes() titlePercent = int(100 * upperWidth / (upperWidth + lowerWidth)) globalref.histOptions.changeValue('TitleSplitPercent', titlePercent) except ZeroDivisionError: pass # skip if splitter sizes were never set tabNum = self.rightTabs.currentIndex() globalref.histOptions.changeValue('ActiveRightView', tabNum) def restoreWindowGeom(self, offset=0): """Restore window geometry from history options. Arguments: offset -- number of pixels to offset window, down and to right """ rect = QRect(globalref.histOptions['WindowXPos'], globalref.histOptions['WindowYPos'], globalref.histOptions['WindowXSize'], globalref.histOptions['WindowYSize']) if rect.x() == -1000 and rect.y() == -1000: # let OS position window the first time self.resize(rect.size()) else: if offset: rect.adjust(offset, offset, offset, offset) availRect = QApplication.primaryScreen().availableVirtualGeometry() topMargin = globalref.histOptions['WindowTopMargin'] otherMargin = globalref.histOptions['WindowOtherMargin'] # remove frame space from available rect availRect.adjust(otherMargin, topMargin, -otherMargin, -otherMargin) finalRect = rect.intersected(availRect) if finalRect.isEmpty(): rect.moveTo(0, 0) finalRect = rect.intersected(availRect) if finalRect.isValid(): self.setGeometry(finalRect) crumbWidth = int(self.breadcrumbSplitter.width() / 100 * globalref.histOptions['CrumbSplitPercent']) self.breadcrumbSplitter.setSizes([crumbWidth, self.breadcrumbSplitter.width() - crumbWidth]) treeWidth = int(self.treeSplitter.width() / 100 * globalref.histOptions['TreeSplitPercent']) self.treeSplitter.setSizes([treeWidth, self.treeSplitter.width() - treeWidth]) outHeight = int(self.outputSplitter.height() / 100.0 * globalref.histOptions['OutputSplitPercent']) self.outputSplitter.setSizes([outHeight, self.outputSplitter.height() - outHeight]) editHeight = int(self.editorSplitter.height() / 100.0 * globalref.histOptions['EditorSplitPercent']) self.editorSplitter.setSizes([editHeight, self.editorSplitter.height() - editHeight]) titleHeight = int(self.titleSplitter.height() / 100.0 * globalref.histOptions['TitleSplitPercent']) self.titleSplitter.setSizes([titleHeight, self.titleSplitter.height() - titleHeight]) self.rightTabs.setCurrentIndex(globalref. histOptions['ActiveRightView']) def resetWindowGeom(self): """Set all stored window geometry values back to default settings. """ globalref.histOptions.resetToDefaults(['WindowXPos', 'WindowYPos', 'WindowXSize', 'WindowYSize', 'CrumbSplitPercent', 'TreeSplitPercent', 'OutputSplitPercent', 'EditorSplitPercent', 'TitleSplitPercent', 'ActiveRightView']) def saveToolbarPosition(self): """Save the toolbar position to the toolbar options. """ toolbarPos = base64.b64encode(self.saveState().data()).decode('ascii') globalref.toolbarOptions.changeValue('ToolbarPosition', toolbarPos) globalref.toolbarOptions.writeFile() def restoreToolbarPosition(self): """Restore the toolbar position from the toolbar options. """ toolbarPos = globalref.toolbarOptions['ToolbarPosition'] if toolbarPos: self.restoreState(base64.b64decode(bytes(toolbarPos, 'ascii'))) def dragEnterEvent(self, event): """Accept drags of files to this window. Arguments: event -- the drag event object """ if event.mimeData().hasUrls(): event.accept() def dropEvent(self, event): """Open a file dropped onto this window. Arguments: event -- the drop event object """ fileList = event.mimeData().urls() if fileList: path = pathlib.Path(fileList[0].toLocalFile()) globalref.mainControl.openFile(path, checkModified=True) def changeEvent(self, event): """Detect an activation of the main window and emit a signal. Arguments: event -- the change event object """ super().changeEvent(event) if (event.type() == QEvent.Type.ActivationChange and QApplication.activeWindow() == self): self.winActivated.emit(self) elif (event.type() == QEvent.Type.WindowStateChange and globalref.genOptions['MinToSysTray'] and self.isMinimized()): self.winMinimized.emit() def closeEvent(self, event): """Signal that the view is closing and close if the flag allows it. Also save window status if necessary. Arguments: event -- the close event object """ self.winClosing.emit(self) if self.allowCloseFlag: event.accept() else: event.ignore() TreeLine-3.2.1/source/undo.py000066400000000000000000000426301506556630100160570ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # undo.py, provides a classes to store and execute undo & redo operations # # TreeLine, an information storage program # Copyright (C) 2018, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import copy import treenode import globalref class UndoRedoList(list): """Stores undo or redo objects. """ def __init__(self, action, localControlRef): """Initialize the undo or redo storage. Set the number of stored levels based on the user option. Arguments: action -- the Qt action for undo/redo menus localControlRef -- ref control class for selections, modified, etc. """ super().__init__() self.action = action self.action.setEnabled(False) self.localControlRef = localControlRef self.levels = globalref.genOptions['UndoLevels'] self.altListRef = None # holds a ref to redo or undo list def addUndoObj(self, undoObject, clearRedo=True): """Add the given undo or redo object to the list. Arguments: undoObject -- the object to be added clearRedo -- if true, clear redo list (can't redo after changes) """ self.append(undoObject) del self[:-self.levels] if self.levels == 0: del self[:] self.action.setEnabled(len(self) > 0) if clearRedo and self.altListRef: self.altListRef.clearList() def clearList(self): """Empty the undo/redo list, primarily for no redo after a change. """ del self[:] self.action.setEnabled(False) def setNumLevels(self): """Change number of stored undo levels to the stored option. """ self.levels = globalref.genOptions['UndoLevels'] del self[:-self.levels] if self.levels == 0: del self[:] self.action.setEnabled(len(self) > 0) def removeLastUndo(self, undoObject): """Remove the last undo object if it matches the given object. Arguments: undoObject -- the object to be removed """ if self[-1] is undoObject: del self[-1] self.action.setEnabled(len(self) > 0) def undo(self): """Save current state to altListRef and restore the last saved state. Remove the last undo item from the list. Restore the previous selection and saved doc modified state. """ # # clear selection to avoid crash due to invalid selection: # self.localControlRef.currentSelectionModel().selectSpots([], False) item = self.pop() item.undo(self.altListRef) selectSpots = [node.spotByNumber(num) for (node, num) in item.selectedTuples] self.localControlRef.currentSelectionModel().selectSpots(selectSpots, False) self.localControlRef.setModified(item.modified) self.action.setEnabled(len(self) > 0) class UndoBase: """Abstract base class for undo objects. """ def __init__(self, localControlRef): """Initialize data storage, selected nodes and doc modified status. Arguments: localControlRef -- ref control class for selections, modified, etc. """ self.dataList = [] self.treeStructRef = localControlRef.structure self.selectedTuples = [(spot.nodeRef, spot.instanceNumber()) for spot in localControlRef.currentSelectionModel(). selectedSpots()] self.modified = localControlRef.modified class DataUndo(UndoBase): """Info for undo/redo of tree node data changes. """ def __init__(self, listRef, nodes, addChildren=False, addBranch=False, skipSame=False, fieldRef='', notRedo=True): """Create the data undo class and add it to the undoStore. Can't use skipSame if addChildren or addBranch are True. Arguments: listRef -- a ref to the undo/redo list this gets added to nodes -- a node or a list of nodes to back up addChildren -- if True, include child nodes addBranch -- if True, include all branch nodes (ignores addChildren skipSame -- if true, don't add an undo that is similar to the last fieldRef -- optional field name ref to check for similar changes notRedo -- if True, clear redo list (after changes) """ super().__init__(listRef.localControlRef) if not isinstance(nodes, list): nodes = [nodes] if (skipSame and listRef and isinstance(listRef[-1], DataUndo) and len(listRef[-1].dataList) == 1 and len(nodes) == 1 and nodes[0] == listRef[-1].dataList[0][0] and fieldRef == listRef[-1].dataList[0][2]): return for node in nodes: if addBranch: for child in node.descendantGen(): self.dataList.append((child, child.data.copy(), '')) else: self.dataList.append((node, node.data.copy(), fieldRef)) if addChildren: for child in node.childList: self.dataList.append((child, child.data.copy(), '')) listRef.addUndoObj(self, notRedo) def undo(self, redoRef): """Save current state to redoRef and restore saved state. Arguments: redoRef -- the redo list where the current state is saved """ if redoRef != None: DataUndo(redoRef, [data[0] for data in self.dataList], False, False, False, '', False) for node, data, fieldRef in self.dataList: node.data = data class ChildListUndo(UndoBase): """Info for undo/redo of tree node child lists. """ def __init__(self, listRef, nodes, addBranch=False, treeFormats=None, skipSame=False, notRedo=True): """Create the child list undo class and add it to the undoStore. Also stores data formats if given. Can't use skipSame if addBranch is True. Arguments: listRef -- a ref to the undo/redo list this gets added to nodes -- a parent node or a list of parents to save children addBranch -- if True, include all branch nodes treeFormats -- the format data to store skipSame -- if true, don't add an undo that is similar to the last notRedo -- if True, clear redo list (after changes) """ super().__init__(listRef.localControlRef) if not isinstance(nodes, list): nodes = [nodes] if (skipSame and listRef and isinstance(listRef[-1], ChildListUndo) and len(listRef[-1].dataList) == 1 and len(nodes) == 1 and nodes[0] == listRef[-1].dataList[0][0]): return self.addBranch = addBranch self.treeFormats = None if treeFormats: self.treeFormats = copy.deepcopy(treeFormats) for node in nodes: if addBranch: for child in node.descendantGen(): self.dataList.append((child, child.childList[:])) else: self.dataList.append((node, node.childList[:])) listRef.addUndoObj(self, notRedo) def undo(self, redoRef): """Save current state to redoRef and restore saved state. Arguments: redoRef -- the redo list where the current state is saved """ if redoRef != None: formats = None if self.treeFormats: formats = self.treeStructRef.treeFormats ChildListUndo(redoRef, [data[0] for data in self.dataList], False, formats, False, False) if self.treeFormats: self.treeStructRef.configDialogFormats = self.treeFormats self.treeStructRef.applyConfigDialogFormats(False) globalref.mainControl.updateConfigDialog() newNodes = set() oldNodes = set() for node, childList in self.dataList: origChildren = set(node.childList) children = set(childList) newNodes = newNodes | (children - origChildren) oldNodes = oldNodes | (origChildren - children) for node, childList in self.dataList: node.childList = childList self.treeStructRef.rebuildNodeDict() # slow but reliable for oldNode in oldNodes: oldNode.removeInvalidSpotRefs() for node, childList in self.dataList: for child in childList: if child in newNodes: child.addSpotRef(node) class ChildDataUndo(UndoBase): """Info for undo/redo of tree node child data and lists. """ def __init__(self, listRef, nodes, addBranch=False, treeFormats=None, notRedo=True): """Create the child data undo class and add it to the undoStore. Arguments: listRef -- a ref to the undo/redo list this gets added to nodes -- a parent node or a list of parents to save children addBranch -- if True, include all branch nodes treeFormats -- the format data to store notRedo -- if True, clear redo list (after changes) """ super().__init__(listRef.localControlRef) if not isinstance(nodes, list): nodes = [nodes] self.addBranch = addBranch self.treeFormats = None if treeFormats: self.treeFormats = copy.deepcopy(treeFormats) for parent in nodes: if addBranch: for node in parent.descendantGen(): self.dataList.append((node, node.data.copy(), node.childList[:])) else: self.dataList.append((parent, parent.data.copy(), parent.childList[:])) for node in parent.childList: self.dataList.append((node, node.data.copy(), node.childList[:])) listRef.addUndoObj(self, notRedo) def undo(self, redoRef): """Save current state to redoRef and restore saved state. Arguments: redoRef -- the redo list where the current state is saved """ if redoRef != None: formats = None if self.treeFormats: formats = self.treeStructRef.treeFormats ChildDataUndo(redoRef, [data[0] for data in self.dataList], False, formats, False) if self.treeFormats: self.treeStructRef.configDialogFormats = self.treeFormats self.treeStructRef.applyConfigDialogFormats(False) globalref.mainControl.updateConfigDialog() newNodes = set() oldNodes = set() for node, data, childList in self.dataList: origChildren = set(node.childList) children = set(childList) newNodes = newNodes | (children - origChildren) oldNodes = oldNodes | (origChildren - children) for node, data, childList in self.dataList: node.childList = childList node.data = data self.treeStructRef.rebuildNodeDict() # slow but reliable for newNode in newNodes.copy(): for child in newNode.descendantGen(): newNodes.add(child) for oldNode in oldNodes: oldNode.removeInvalidSpotRefs() for node, data, childList in self.dataList: for child in childList: if child in newNodes: child.addSpotRef(node, not self.addBranch) class TypeUndo(UndoBase): """Info for undo/redo of tree node type name changes. Also saves node data to cover blank node title replacement and initial data settings. """ def __init__(self, listRef, nodes, notRedo=True): """Create the data undo class and add it to the undoStore. Arguments: listRef -- a ref to the undo/redo list this gets added to nodes -- a node or a list of nodes to back up notRedo -- if True, add clones and clear redo list (after changes) """ super().__init__(listRef.localControlRef) if not isinstance(nodes, list): nodes = [nodes] for node in nodes: self.dataList.append((node, node.formatRef.name, node.data.copy())) listRef.addUndoObj(self, notRedo) def undo(self, redoRef): """Save current state to redoRef and restore saved state. Arguments: redoRef -- the redo list where the current state is saved """ if redoRef != None: TypeUndo(redoRef, [data[0] for data in self.dataList], False) for node, formatName, data in self.dataList: node.formatRef = self.treeStructRef.treeFormats[formatName] node.data = data class FormatUndo(UndoBase): """Info for undo/redo of tree node type format changes. """ def __init__(self, listRef, origTreeFormats, newTreeFormats, notRedo=True): """Create the data undo class and add it to the undoStore. Arguments: listRef -- a ref to the undo/redo list this gets added to origTreeFormats -- the format data to store newTreeFormats -- the replacement format, contains rename dicts notRedo -- if True, clear redo list (after changes) """ super().__init__(listRef.localControlRef) self.treeFormats = copy.deepcopy(origTreeFormats) self.treeFormats.fieldRenameDict = {} for typeName, fieldDict in newTreeFormats.fieldRenameDict.items(): self.treeFormats.fieldRenameDict[typeName] = {} for oldName, newName in fieldDict.items(): self.treeFormats.fieldRenameDict[typeName][newName] = oldName self.treeFormats.typeRenameDict = {} for oldName, newName in newTreeFormats.typeRenameDict.items(): self.treeFormats.typeRenameDict[newName] = oldName if newName in self.treeFormats.fieldRenameDict: self.treeFormats.fieldRenameDict[oldName] = (self.treeFormats. fieldRenameDict[newName]) del self.treeFormats.fieldRenameDict[newName] listRef.addUndoObj(self, notRedo) def undo(self, redoRef): """Save current state to redoRef and restore saved state. Arguments: redoRef -- the redo list where the current state is saved """ if redoRef != None: FormatUndo(redoRef, self.treeStructRef.treeFormats, self.treeFormats, False) self.treeStructRef.configDialogFormats = self.treeFormats self.treeStructRef.applyConfigDialogFormats(False) globalref.mainControl.updateConfigDialog() class ParamUndo(UndoBase): """Info for undo/redo of any variable parameter. """ def __init__(self, listRef, varList, notRedo=True): """Create the data undo class and add it to the undoStore. Arguments: listRef -- a ref to the undo/redo list this gets added to varList - list of tuples, variable's owner and variable's name notRedo -- if True, clear redo list (after changes) """ super().__init__(listRef.localControlRef) for varOwner, varName in varList: value = varOwner.__dict__[varName] self.dataList.append((varOwner, varName, value)) listRef.addUndoObj(self, notRedo) def undo(self, redoRef): """Save current state to redoRef and restore saved state. Arguments: redoRef -- the redo list where the current state is saved """ if redoRef != None: ParamUndo(redoRef, [item[:2] for item in self.dataList], False) for varOwner, varName, value in self.dataList: varOwner.__dict__[varName] = value class StateSettingUndo(UndoBase): """Info for undo/redo of objects with get/set functions for attributes. """ def __init__(self, listRef, getFunction, setFunction, notRedo=True): """Create the data undo class and add it to the undoStore. Arguments: listRef -- a ref to the undo/redo list this gets added to getFunction -- a function ref that returns a state variable setFunction -- a function ref that restores from the state varible notRedo -- if True, clear redo list (after changes) """ super().__init__(listRef.localControlRef) self.getFunction = getFunction self.setFunction = setFunction self.data = getFunction() listRef.addUndoObj(self, notRedo) def undo(self, redoRef): """Save current state to redoRef and restore saved state. Arguments: redoRef -- the redo list where the current state is saved """ if redoRef != None: StateSettingUndo(redoRef, self.getFunction, self.setFunction, False) self.setFunction(self.data) TreeLine-3.2.1/source/urltools.py000066400000000000000000000112411506556630100167670ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # urltools.py, provides functions for parsing and modifying URLs. # # TreeLine, an information storage program # Copyright (C) 2018, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import re import sys import os.path _urlRegExp = re.compile(r'([a-z]{2,}://)?(?:/?([a-z]:))?(.*)', re.IGNORECASE) def splitUrl(url): """Return a tuple of scheme, drive letter and address. If any are not present, return empty strings. Arguments: url -- a string with the original URL """ if os.sep == '\\': url = url.replace('\\', '/') scheme, drive, address = _urlRegExp.match(url).groups('') scheme = scheme[:-3] if not scheme and url.startswith('mailto:'): scheme = 'mailto' drive = '' address = url[7:] return (scheme, drive, address) def extractScheme(url): """Return the scheme from this URL, or an empty string if none is given. Arguments: url -- a string with the original URL """ scheme, drive, address = splitUrl(url) return scheme def extractAddress(url): """Remove the scheme from this URL and return the address. Includes the drive letter if present. Arguments: url -- a string with the original URL """ scheme, drive, address = splitUrl(url) return drive + address def replaceScheme(scheme, url): """Replace any scheme in url with the given scheme and return. The scheme is not included with a relative file path. Arguments: scheme -- the new scheme to add url -- the address be modified """ oldScheme, drive, address = splitUrl(url) if drive: drive = '/' + drive elif scheme == 'file' and not address.startswith('/'): return address elif scheme == 'mailto': return '{0}:{1}'.format(scheme, address) return '{0}://{1}{2}'.format(scheme, drive, address) def shortName(url): """Return a default short name using the base portion of the URL filename. Arguments: url -- a string with the original URL """ scheme, drive, address = splitUrl(url) name = os.path.basename(address) if not name: # remove trailing separator if there is no basename name = os.path.basename(address[:-1]) if scheme == 'mailto' or '@' in name: name = name.split('@', 1)[0] return name def isRelative(url): """Return true if this URL is a relative path. Any scheme or drive letter is considered absolute and returns false. Arguments: url -- a string with the original URL """ scheme, drive, address = splitUrl(url) if scheme or drive or address.startswith('/'): return False return True def toAbsolute(url, refPath, addScheme=True): """Convert a relative file URL to an absolute URL and return it. Arguments: url -- a string with the original URL refPath -- the path that the URL is relative to addScheme -- add the 'file' scheme to result if true """ scheme, drive, address = splitUrl(url) url = os.path.normpath(os.path.join(refPath, drive + address)) if addScheme: return replaceScheme('file', url) if os.sep == '\\': url = url.replace('\\', '/') return url def toRelative(url, refPath): """Convert an absolute file URL to a relative URL and return it. Arguments: url -- a string with the original URL refPath -- the path that the URL is relative to """ scheme, drive, address = splitUrl(url) if drive or address.startswith('/'): try: url = os.path.relpath(drive + address, refPath) except ValueError: pass if os.sep == '\\': url = url.replace('\\', '/') return url def which(fileName): """Return the full path if the fileName is found somewhere in the PATH. If not found, return an empty string. Similar to the Linux which command. Arguments: fileName -- the name to search for """ extList = [''] if sys.platform.startswith('win'): extList.extend(os.getenv('PATHEXT', '').split(os.pathsep)) for path in os.get_exec_path(): for ext in extList: fullPath = os.path.join(path, fileName + ext) if os.access(fullPath, os.X_OK): return fullPath return '' TreeLine-3.2.1/templates/000077500000000000000000000000001506556630100152315ustar00rootroot00000000000000TreeLine-3.2.1/templates/110en_Long_Text.trln000066400000000000000000000021041506556630100207360ustar00rootroot00000000000000{ "formats": [ { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Text", "fieldtype": "Text", "lines": 8 } ], "formatname": "LONG_TEXT", "outputlines": [ "{*Name*}", "{*Text*}" ], "titleline": "{*Name*}" } ], "nodes": [ { "children": [ "d8ef9244959111e7a8357054d2175f18" ], "data": { "Name": "Parent", "Text": "Parent text" }, "format": "LONG_TEXT", "uid": "d8ef8eb6959111e7a8357054d2175f18" }, { "children": [], "data": { "Name": "Child", "Text": "Child text" }, "format": "LONG_TEXT", "uid": "d8ef9244959111e7a8357054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "d8ef8eb6959111e7a8357054d2175f18" ] } }TreeLine-3.2.1/templates/210en_Contact_List.trln000066400000000000000000000073601506556630100214330ustar00rootroot00000000000000{ "formats": [ { "childtype": "PERSON", "fields": [ { "fieldname": "Type", "fieldtype": "Text" } ], "formatname": "CATEGORY", "outputlines": [ "{*Type*}" ], "titleline": "{*Type*}" }, { "fields": [ { "fieldname": "FirstName", "fieldtype": "Text", "sortkeynum": 2 }, { "fieldname": "LastName", "fieldtype": "Text", "sortkeynum": 1 }, { "fieldname": "Street", "fieldtype": "Text" }, { "fieldname": "City", "fieldtype": "Text" }, { "fieldname": "State", "fieldtype": "Text" }, { "fieldname": "Zip", "fieldtype": "Text" }, { "fieldname": "HomePhone", "fieldtype": "Text" }, { "fieldname": "WorkPhone", "fieldtype": "Text" }, { "fieldname": "MobilePhone", "fieldtype": "Text" }, { "fieldname": "Birthday", "fieldtype": "Date", "format": "%B %-d, %Y" }, { "fieldname": "Email", "fieldtype": "Text" } ], "formatname": "PERSON", "outputlines": [ "{*FirstName*} {*LastName*}", "{*Street*}", "{*City*}, {*State*} {*Zip*}", "{*HomePhone*} (H)", "{*WorkPhone*} (W)", "{*MobilePhone*} (M)", "DoB: {*Birthday*}", "{*Email*}" ], "titleline": "{*FirstName*} {*LastName*}" } ], "nodes": [ { "children": [ "f402b796959111e7a8357054d2175f18", "f402c33a959111e7a8357054d2175f18" ], "data": { "Type": "Main" }, "format": "CATEGORY", "uid": "f402b5ac959111e7a8357054d2175f18" }, { "children": [ "f402be26959111e7a8357054d2175f18" ], "data": { "Type": "Friends" }, "format": "CATEGORY", "uid": "f402b796959111e7a8357054d2175f18" }, { "children": [], "data": { "City": "Atlantis", "Email": "john.doe@nowhere.com", "FirstName": "John", "HomePhone": "(123) 555-4567", "LastName": "Doe", "State": "CA", "Street": "1492 Columbus Lane", "WorkPhone": "(123) 555-9876", "Zip": "98765" }, "format": "PERSON", "uid": "f402be26959111e7a8357054d2175f18" }, { "children": [ "f402c448959111e7a8357054d2175f18" ], "data": { "Type": "Family" }, "format": "CATEGORY", "uid": "f402c33a959111e7a8357054d2175f18" }, { "children": [], "data": { "Birthday": "1955-02-08", "City": "Britania", "FirstName": "Jane", "HomePhone": "(123) 490-4909", "LastName": "Roe", "State": "NM", "Street": "1812 War Lane", "Zip": "87560" }, "format": "PERSON", "uid": "f402c448959111e7a8357054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "f402b5ac959111e7a8357054d2175f18" ] } }TreeLine-3.2.1/templates/220en_Book_List.trln000066400000000000000000000064731506556630100207370ustar00rootroot00000000000000{ "formats": [ { "childtype": "BOOK", "fields": [ { "fieldname": "AuthorFirstName", "fieldtype": "Text", "sortkeynum": 2 }, { "fieldname": "AuthorLastName", "fieldtype": "Text", "sortkeynum": 1 } ], "formatname": "AUTHOR", "icon": "book_3", "outputlines": [ "{*AuthorFirstName*} {*AuthorLastName*}" ], "titleline": "{*AuthorFirstName*} {*AuthorLastName*}" }, { "fields": [ { "fieldname": "Title", "fieldtype": "Text", "sortkeynum": 2 }, { "fieldname": "Copyright", "fieldtype": "Number", "format": "0000", "sortkeynum": 1 }, { "fieldname": "ReadDate", "fieldtype": "Date", "format": "%B, %Y" }, { "fieldname": "Plot", "fieldtype": "Text" } ], "formatname": "BOOK", "icon": "book_1", "outputlines": [ "\"{*Title*}\"", "(c) {*Copyright*}", "Last Read: {*ReadDate*}", "{*Plot*}" ], "titleline": "\"{*Title*}\"" }, { "childtype": "AUTHOR", "fields": [ { "fieldname": "NAME", "fieldtype": "Text" } ], "formatname": "CATEGORY", "outputlines": [ "{*NAME*}" ], "titleline": "{*NAME*}" } ], "nodes": [ { "children": [ "0b7bffe0959211e7a8357054d2175f18", "0b7c0850959211e7a8357054d2175f18" ], "data": { "NAME": "SF Books" }, "format": "CATEGORY", "uid": "0b7bfb76959211e7a8357054d2175f18" }, { "children": [ "0b7c0530959211e7a8357054d2175f18" ], "data": { "AuthorFirstName": "Orson Scott", "AuthorLastName": "Card" }, "format": "AUTHOR", "uid": "0b7bffe0959211e7a8357054d2175f18" }, { "children": [], "data": { "Copyright": "1985", "Plot": "Young boy is taught fighting and leadership", "ReadDate": "2007-04-30", "Title": "Ender's Game" }, "format": "BOOK", "uid": "0b7c0530959211e7a8357054d2175f18" }, { "children": [ "0b7c0968959211e7a8357054d2175f18" ], "data": { "AuthorFirstName": "Isaac", "AuthorLastName": "Asimov" }, "format": "AUTHOR", "uid": "0b7c0850959211e7a8357054d2175f18" }, { "children": [], "data": { "Copyright": "1951", "Plot": "Psychohistory predicts the fall of empire", "Title": "Foundation" }, "format": "BOOK", "uid": "0b7c0968959211e7a8357054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "0b7bfb76959211e7a8357054d2175f18" ] } }TreeLine-3.2.1/templates/230en_ToDo_List.trln000066400000000000000000000077111506556630100207070ustar00rootroot00000000000000{ "formats": [ { "childtype": "TASK_UNDONE", "fields": [ { "fieldname": "Name", "fieldtype": "Text" } ], "formathtml": true, "formatname": "CATEGORY", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "condition": "Done == \"true\"", "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Done", "fieldtype": "Boolean", "format": "yes/no", "init": "false" }, { "fieldname": "Urgent", "fieldtype": "Boolean", "format": "yes/no", "init": "false" } ], "formathtml": true, "formatname": "TASK_DONE", "icon": "smiley_4", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Done", "fieldtype": "Boolean", "format": "yes/no", "init": "false" }, { "fieldname": "Urgent", "fieldtype": "Boolean", "format": "yes/no", "init": "false" } ], "formathtml": true, "formatname": "TASK_UNDONE", "generic": "TASK_DONE", "icon": "smiley_2", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}" }, { "condition": "Done == \"false\" and Urgent == \"true\"", "fields": [ { "fieldname": "Name", "fieldtype": "Text" }, { "fieldname": "Done", "fieldtype": "Boolean", "format": "yes/no", "init": "false" }, { "fieldname": "Urgent", "fieldtype": "Boolean", "format": "yes/no", "init": "true" } ], "formathtml": true, "formatname": "TASK_UNDONE_URGENT", "generic": "TASK_DONE", "icon": "smiley_5", "outputlines": [ "{*Name*}" ], "titleline": "{*Name*}!!!" } ], "nodes": [ { "children": [ "1d1b7e56959211e7a8357054d2175f18", "1d1b857c959211e7a8357054d2175f18" ], "data": { "Name": "Conditional Task List" }, "format": "CATEGORY", "uid": "1d1b7c9e959211e7a8357054d2175f18" }, { "children": [ "1d1b81b2959211e7a8357054d2175f18" ], "data": { "Name": "Home Tasks" }, "format": "CATEGORY", "uid": "1d1b7e56959211e7a8357054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Mow lawn", "Urgent": "false" }, "format": "TASK_UNDONE", "uid": "1d1b81b2959211e7a8357054d2175f18" }, { "children": [ "1d1b868a959211e7a8357054d2175f18" ], "data": { "Name": "Work Tasks" }, "format": "CATEGORY", "uid": "1d1b857c959211e7a8357054d2175f18" }, { "children": [], "data": { "Done": "false", "Name": "Write documents", "Urgent": "false" }, "format": "TASK_UNDONE", "uid": "1d1b868a959211e7a8357054d2175f18" } ], "properties": { "tlversion": "2.9.0", "topnodes": [ "1d1b7c9e959211e7a8357054d2175f18" ] } }TreeLine-3.2.1/templates/exports/000077500000000000000000000000001506556630100167355ustar00rootroot00000000000000TreeLine-3.2.1/templates/exports/live_tree_export.css000066400000000000000000000011271506556630100230270ustar00rootroot00000000000000/* live_tree_export.css, provides css for a read-only TreeLine view */ body { background-color: white; color: black; } #tree { width: 40%; height: 100%; top: 0; left: 0; position: fixed; overflow: scroll; } #tree ul { cursor: default; list-style-type: none; } #tree li { text-indent: -1.3em; } .marker { font-size: 0.8em; display: inline-block; width: 1.3em; text-align: center; vertical-align: middle; color: blue; } .selected { color: red; } #output { margin-left: 41%; } #output div { padding-left: 2em; } TreeLine-3.2.1/templates/exports/live_tree_export.html000066400000000000000000000010441506556630100232010ustar00rootroot00000000000000 TreeLine Export
      TreeLine-3.2.1/templates/exports/live_tree_export.js000066400000000000000000001153371506556630100226640ustar00rootroot00000000000000// live_tree_export.js, provides javascript code for a read-only tree view // Works with TreeLine, an information storage program // Copyright (C) 2023, Douglas W. Bell // This is free software; you can redistribute it and/or modify it under the // terms of the GNU General Public License, either Version 2 or any later // version. This program is distributed in the hope that it will be useful, // but WITTHOUT ANY WARRANTY. See the included LICENSE file for details. "use strict"; var spotDict = {}; var rootSpots = []; var treeFormats = {}; var selectedSpot = null; var openMarker = "\u2296"; var closedMarker = "\u2295"; var leafMarker = "\u25CB"; function main() { if (dataFileName) { if (dataFilePath) { dataFileName = dataFilePath + "/" + dataFileName; } loadFile(dataFileName); } else { loadData(document.getElementById("json").innerHTML); } } function loadFile(filePath) { // initial load from file link var xhttp = new XMLHttpRequest(); xhttp.overrideMimeType("application/json"); xhttp.open("GET", filePath, true); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { loadData(this.responseText); } } xhttp.send(null); } function loadData(textData) { // initial load from file data var fileData = JSON.parse(textData); fileData.formats.forEach(function(formatData) { var formatName = formatData.formatname; treeFormats[formatName] = new NodeFormat(formatData); }); var node, spot; fileData.nodes.forEach(function(nodeData) { node = new TreeNode(treeFormats[nodeData.format], nodeData); spot = new TreeSpot(node, nodeData.uid); }); rootSpots = fileData.properties.topnodes.map(function(id) { return spotDict[id]; }); rootSpots.forEach(function(rootSpot) { rootSpot.nodeRef.assignRefs(null); }); var rootElement = document.getElementById("rootlist"); rootSpots.forEach(function(rootSpot) { if (rootSpot.nodeRef.childList.length > 0) rootSpot.open = true; rootSpot.outputElement(rootElement); }); } function TreeSpot(nodeRef, uId) { // class to store node positions (unique even for cloned nodes) this.nodeRef = nodeRef; this.uId = uId; this.parentSpot; this.open = false; spotDict[uId] = this; nodeRef.spotRefs.push(this); } TreeSpot.prototype.childSpots = function() { // return an array of child spots return this.nodeRef.childList.map(function(node) { return node.matchedSpot(this); }, this); } TreeSpot.prototype.outputElement = function(parentElement) { // recursively output html tree elements var node = this.nodeRef; var element = document.createElement("li"); var markerSpan = document.createElement("span"); var markerText = leafMarker; if (node.childList.length > 0) { markerText = this.open ? openMarker : closedMarker; } markerSpan.appendChild(document.createTextNode(markerText)); markerSpan.className = "marker"; element.appendChild(markerSpan); var textSpan = document.createElement("span"); textSpan.appendChild(document.createTextNode(node.formatRef. formatTitle(this))); textSpan.className = "nodetext"; element.appendChild(textSpan); element.setAttribute("id", this.uId); parentElement.appendChild(element); if (this.open && node.childList.length > 0) this.openChildren(element); } TreeSpot.prototype.openChildren = function(parentElement) { // output children of this node var listElement = document.createElement("ul"); parentElement.appendChild(listElement); this.childSpots().forEach(function(childSpot) { childSpot.outputElement(listElement); }); } TreeSpot.prototype.toggleOpen = function() { // toggle this spot's opened/closed state if (this.nodeRef.childList.length == 0) return; this.open = !this.open; var element = document.getElementById(this.uId); if (this.open) { element.childNodes[0].innerHTML = openMarker; this.openChildren(element); } else { element.childNodes[0].innerHTML = closedMarker; var elementList = element.childNodes; for (var i = 0; i < elementList.length; i++) { if (elementList[i].tagName == "UL") { element.removeChild(elementList[i]); } } } } TreeSpot.prototype.openParents = function() { // open all parent spots of this spot var ancestors = []; var spot = this.parentSpot; var element; while (spot) { ancestors.unshift(spot); spot = spot.parentSpot; } ancestors.forEach(function(ancestor) { if (!ancestor.open) { ancestor.open = true; element = document.getElementById(ancestor.uId); element.childNodes[0].innerHTML = openMarker; ancestor.openChildren(element); } }); } TreeSpot.prototype.select = function() { // change selection to this var prevSpot = selectedSpot; selectedSpot = this; if (prevSpot) { var prevElem = document.getElementById(prevSpot.uId); if (prevElem) prevElem.childNodes[1].classList.remove("selected"); } var element = document.getElementById(this.uId); element.childNodes[1].classList.add("selected"); var outputGroup = new OutputGroup(); document.getElementById("output").innerHTML = outputGroup.getText(); } TreeSpot.prototype.prevTreeSpot = function() { // return the previous open spot in tree order var pos, node, sibling; if (this.parentSpot) { pos = this.parentSpot.nodeRef.childList.indexOf(this.nodeRef); if (pos <= 0) return this.parentSpot; node = this.parentSpot.nodeRef.childList[pos - 1]; sibling = node.matchedSpot(this.parentSpot); } else { pos = rootSpots.indexOf(this); if (pos <= 0) return null; sibling = rootSpots[pos - 1]; } while (sibling.open) { node = sibling.nodeRef.childList[sibling.nodeRef.childList. length - 1]; sibling = node.matchedSpot(sibling); } return sibling; } TreeSpot.prototype.nextTreeSpot = function() { // return the next open spot in tree order if (this.open) { return this.nodeRef.childList[0].matchedSpot(this); } var pos, sibling; var ancestor = this; while (ancestor.parentSpot) { pos = ancestor.parentSpot.nodeRef.childList.indexOf(ancestor.nodeRef); sibling = ancestor.parentSpot.nodeRef.childList[pos + 1]; if (sibling) { return sibling.matchedSpot(ancestor.parentSpot); } ancestor = ancestor.parentSpot; } pos = rootSpots.indexOf(ancestor); sibling = rootSpots[pos + 1]; if (sibling) return sibling; return null; } function TreeNode(formatRef, fileData) { // class to store nodes this.formatRef = formatRef; this.data = fileData.data; this.tmpChildRefs = fileData.children; this.spotRefs = []; this.childList = []; } TreeNode.prototype.assignRefs = function(parentSpot) { // recursively add actual refs to child nodes and parent spots var spot = this.spotRefs[0]; if (spot.parentSpot !== undefined) { // cloned node var id = spot.uId; var num = 1; do { id = id + "_" + num; num += 1; } while (id in spotDict); spot = new TreeSpot(this, id); } spot.parentSpot = parentSpot; this.childList.forEach(function(child) { // for clones (2nd time thru) child.assignRefs(spot); }); var childNode; this.tmpChildRefs.forEach(function(childId) { // for first time thru childNode = spotDict[childId].nodeRef; this.childList.push(childNode); childNode.assignRefs(spot); }, this); this.tmpChildRefs = []; } TreeNode.prototype.matchedSpot = function(parentSpot) { // return the spot for this node that matches the given parent spot for (var i = 0; i < this.spotRefs.length; i++) { if (this.spotRefs[i].parentSpot === parentSpot) { return this.spotRefs[i]; } } return null; } function NodeFormat(formatData) { // class to store node format data and format output this.fieldDict = {}; formatData.fields.forEach(function(fieldData) { this.fieldDict[fieldData.fieldname] = new FieldFormat(fieldData); }, this); this.spaceBetween = valueOrDefault(formatData, "spacebetween", true); this.formatHtml = valueOrDefault(formatData, "formathtml", false); this.outputSeparator = valueOrDefault(formatData, "outputsep", ", "); this.siblingPrefix = ""; this.siblingSuffix = ""; this.titleLine = this.parseLine(formatData.titleline); var lines = formatData.outputlines; this.useBullets = valueOrDefault(formatData, "bullets", false); if (this.useBullets) { this.siblingPrefix = "
        "; this.siblingSuffix = "
      "; if (lines != [""]) { lines[0] = "
    • " + lines[0]; lines[lines.length - 1] += "
    • "; } } this.useTables = valueOrDefault(formatData, "tables", false); if (this.useTables) { lines = lines.filter(String); var newLines = []; var headings = []; var head, firstPart, parts; lines.forEach(function(line) { head = ""; firstPart = this.parseLine(line)[0]; if (typeof firstPart == "string" && firstPart.indexOf(":") >= 0) { parts = line.split(":"); head = parts.shift(); line = parts.join(""); } newLines.push(line.trim()); headings.push(head.trim()); }, this); this.siblingPrefix = ''; if (headings.filter(String).length > 0) { this.siblingPrefix += ""; headings.forEach(function(hd) { this.siblingPrefix += ""; }, this); this.siblingPrefix += ""; } this.siblingSuffix = "
      " + hd + "
      "; lines = newLines.map(function(line) { return "" + line + ""; }); lines[0] = "" + lines[0]; lines[lines.length - 1] += ""; } this.outputLines = lines.map(this.parseLine, this); } NodeFormat.prototype.parseLine = function(text) { // parse text with embedded fields, return list of fields and text var segments = text.split(/({\*(?:\**|\?|!|&|#)[\w_\-.]+\*})/g); return segments.map(this.parseField, this).filter(String); } NodeFormat.prototype.parseField = function(text) { // parse text field, return field type or plain text if not a field var field; var match = /{\*(\**|\?|!|&|#)([\w_\-.]+)\*}/g.exec(text); if (match) { var modifier = match[1]; var fieldName = match[2]; if (modifier == "" && fieldName in this.fieldDict) { return this.fieldDict[fieldName]; } else if (modifier.match(/^\*+$/)) { field = new FieldFormat({"fieldname": fieldName, "fieldtype": "AncestorLevel"}); field.ancestorLevel = modifier.length; field.placeholder = true; return field; } else if (modifier == "?") { field = new FieldFormat({"fieldname": fieldName, "fieldtype": "AnyAncestor"}); field.placeholder = true; return field; } else if (modifier == "&") { field = new FieldFormat({"fieldname": fieldName, "fieldtype": "ChildList"}); field.placeholder = true; return field; } else if (modifier == "#") { match = /[^0-9]+([0-9]+)$/.exec(fieldName); if (match && match[1] != "0") { field = new FieldFormat({"fieldname": fieldName, "fieldtype": "DescendantCount"}); field.descendantLevel = Number(match[1]); field.placeholder = true; return field; } } else if (modifier == "!") { field = new FieldFormat({"fieldname": fieldName, "fieldtype": "StaticFileInfo"}); if (fieldName == "File_Name") { field.staticInfo = dataFileName; } else if (fieldName == "File_Path") { field.staticInfo = dataFilePath; } field.placeholder = true; return field; } } return text; } NodeFormat.prototype.formatTitle = function(spot) { // return a string with formatted title data var result = this.titleLine.map(function(part) { if (typeof part.outputText === "function") { return part.outputText(spot, true, this.formatHtml); } return part; }, this); return result.join("").trim().split("\n", 1)[0]; } NodeFormat.prototype.formatOutput = function(spot, keepBlanks) { // return a list of formatted text output lines var line, numEmptyFields, numFullFields, text, match; var result = []; this.outputLines.forEach(function(lineData) { line = ""; numEmptyFields = 0; numFullFields = 0; lineData.forEach(function(part) { if (typeof part.outputText === "function") { text = part.outputText(spot, false, this.formatHtml); if (text) { numFullFields += 1; } else { numEmptyFields += 1; } line += text; } else { if (!this.formatHtml) { part = escapeHtml(part); } line += part; } }, this); if (keepBlanks || numFullFields > 0 || numEmptyFields == 0) { result.push(line); } else if (this.formatHtml && result.length > 0) { match = /.*(|)$/gi.exec(line); if (match) { result[result.length - 1] += match[1]; } } }, this); return result; } function FieldFormat(fieldData) { // class to store field format data and format field output this.name = fieldData.fieldname; this.fieldType = fieldData.fieldtype; this.format = valueOrDefault(fieldData, "format", ""); this.prefix = valueOrDefault(fieldData, "prefix", ""); this.suffix = valueOrDefault(fieldData, "suffix", ""); this.mathResultType = valueOrDefault(fieldData, "resulttype", "number"); this.placeholder = false; this.ancestorLevel = 0; this.descendantLevel = 0; this.staticInfo = ""; if (this.fieldType == "Numbering") { this.numberingFormats = initNumbering(this.format); } if (this.fieldType == "Choice" || this.fieldType == "Combination") { var formatText = this.format.replace(/\/\//g, "\0"); if (valueOrDefault(fieldData, "evalhtml", false)) { formatText = escapeHtml(formatText); } this.choiceList = formatText.split("/").map(function(text) { return text.replace(/\0/g, "/"); }); } } FieldFormat.prototype.outputText = function(spot, titleMode, formatHtml) { // return formatted output text for this field in this node var splitValue, outputSep, selections, result, match, i, field; var newNodes, prevNodes; var value = valueOrDefault(spot.nodeRef.data, this.name, ""); if (!value && !this.placeholder) return ""; switch (this.fieldType) { case "OneLineText": value = value.split("
      ", 1)[0]; break; case "SpacedText": value = "
      " + value + "
      "; break; case "Number": var num = Number(value); value = formatNumber(num, this.format); break; case "Math": if (this.mathResultType == "number") { var num = Number(value); value = formatNumber(num, this.format); } else if (this.mathResultType == "date") { value = formatDate(value, this.format); } else if (this.mathResultType == "time") { value = formatTime(value, this.format); } else if (this.mathResultType == "boolean") { value = formatBoolean(value, this.format); } break; case "Numbering": value = formatNumbering(value, this.numberingFormats); break; case "Date": value = formatDate(value, this.format); break; case "Time": value = formatTime(value, this.format); break; case "DateTime": splitValue = value.split(" "); value = formatDate(splitValue[0], this.format); value = formatTime(splitValue[1], value); break; case "Choice": if (this.choiceList.indexOf(value) < 0) value = "#####"; break; case "Combination": outputSep = spot.nodeRef.formatRef.outputSeparator; value = value.replace(/\/\//g, "\0"); selections = value.split("/").map(function(text) { return text.replace(/\0/g, "/"); }); result = this.choiceList.filter(function(text) { return selections.indexOf(text) >= 0; }); if (result.length == selections.length) { value = result.join(outputSep); } else { value = "#####"; } break; case "AutoCombination": outputSep = spot.nodeRef.formatRef.outputSeparator; value = value.replace(/\/\//g, "\0"); selections = value.split("/").map(function(text) { return text.replace(/\0/g, "/"); }); value = selections.join(outputSep); break; case "Boolean": value = formatBoolean(value, this.format); break; case "ExternalLink": case "InternalLink": if (titleMode) { match = /
      ]*href="([^"]+)"[^>]*>([\S\s]*?)<\/a>/i. exec(value); if (match) { value = match[2].trim(); if (!value) { value = match[1]; if (value.startsWith("#")) value = value.substr(1); } } } break; case "Picture": if (titleMode) { match = /]*src="([^"]+)"[^>]*>/i.exec(value); if (match) value = match(1).trim(); } break; case "RegularExpression": match = new RegExp(this.format).exec(unescapeHtml(value)); if (!match || match[0] != unescapeHtml(value)) { value = "#####"; } break; case "AncestorLevel": value = ""; for (i = 0; i < this.ancestorLevel; i++) { spot = spot.parentSpot; } if (spot) { field = spot.nodeRef.formatRef.fieldDict[this.name]; if (field) { value = field.outputText(spot, titleMode, formatHtml); } } break; case "AnyAncestor": value = ""; while (spot.parentSpot) { spot = spot.parentSpot; field = spot.nodeRef.formatRef.fieldDict[this.name]; if (field) { value = field.outputText(spot, titleMode, formatHtml); break; } } break; case "ChildList": result = []; spot.childSpots().forEach(function(childSpot) { field = childSpot.nodeRef.formatRef.fieldDict[this.name]; if (field) { result.push(field.outputText(childSpot, titleMode, formatHtml)); } }, this); outputSep = spot.nodeRef.formatRef.outputSeparator; value = result.join(outputSep); break; case "DescendantCount": newNodes = [spot.nodeRef]; for (i = 0; i < this.descendantLevel; i++) { prevNodes = newNodes; newNodes = []; prevNodes.forEach(function(child) { newNodes = newNodes.concat(child.childList); }); } value = newNodes.length.toString(); break; case "StaticFileInfo": value = this.staticInfo; break; } var prefix = this.prefix; var suffix = this.suffix; if (titleMode) { value = removeMarkup(value); if (formatHtml) { prefix = removeMarkup(prefix); suffix = removeMarkup(suffix); } } else if (!formatHtml) { prefix = escapeHtml(prefix); suffix = escapeHtml(suffix); } return prefix + value + suffix; } function OutputItem(spot, level) { // class to store output for a single node var format = spot.nodeRef.formatRef; if (format.useTables) { this.textLines = format.formatOutput(spot, true); } else { this.textLines = format.formatOutput(spot, false). map(function(line) { return line + "
      "; }); } this.level = level; this.uId = spot.uId; this.addSpace = format.spaceBetween; this.siblingPrefix = format.siblingPrefix; this.siblingSuffix = format.siblingSuffix; if (format.useBullets && this.textLines.length > 0) { this.textLines[this.textLines.length - 1] = this.textLines[this.textLines.length - 1].slice(0, -6); } } OutputItem.prototype.addIndent = function(prevLevel, nextLevel) { // add
      tags to define indent levels in the output var i; for (i = 0; i < this.level - prevLevel; i++) { this.textLines[0] = "
      " + this.textLines[0]; } for (i = 0; i < this.level - nextLevel; i++) { this.textLines[this.textLines.length - 1] += "
      "; } } OutputItem.prototype.addSiblingPrefix = function() { // add the sibling prefix before this output if (this.siblingPrefix) { this.textLines[0] = this.siblingPrefix + this.textLines[0]; } } OutputItem.prototype.addSiblingSuffix = function() { // add the sibling suffix after this output if (this.siblingSuffix) { this.textLines[this.textLines.length - 1] += this.siblingSuffix; } } OutputItem.prototype.equalPrefix = function(otherItem) { // return true if sibling prefixes and suffixes are equal return (this.siblingPrefix == otherItem.siblingPrefix && this.siblingSuffix == otherItem.siblingSuffix); } function OutputGroup() { // class to store and modify output lines this.itemList = []; if (selectedSpot) { this.itemList.push(new OutputItem(selectedSpot, 0)); this.addChildren(selectedSpot, 0); if (this.hasPrefixes()) this.combineAllSiblings(); this.addBlanksBetween(); this.addIndents(); } } OutputGroup.prototype.addChildren = function(spot, level) { // recursively add output items for descendants spot.childSpots().forEach(function(childSpot) { this.itemList.push(new OutputItem(childSpot, level + 1)); this.addChildren(childSpot, level + 1); }, this); } OutputGroup.prototype.addBlanksBetween = function() { // add blank lines between items based on node format for (var i = 0; i < this.itemList.length - 1; i++) { if (this.itemList[i].addSpace || this.itemList[i + 1].addSpace) { var lines = this.itemList[i].textLines; lines[lines.length - 1] += "
      " } } } OutputGroup.prototype.addIndents = function() { // add nested
      elements to define indentations in the output var prevLevel = 0; var nextLevel; for (var i = 0; i < this.itemList.length; i++) { if (i + 1 < this.itemList.length) { nextLevel = this.itemList[i + 1].level; } else { nextLevel = 0; } this.itemList[i].addIndent(prevLevel, nextLevel); prevLevel = this.itemList[i].level; } } OutputGroup.prototype.hasPrefixes = function() { // return true if sibling prefixes or suffixes are found var items = this.itemList.filter(function(item) { return item.siblingPrefix || item.siblingSuffix; }); return items.length > 0; } OutputGroup.prototype.combineAllSiblings = function() { // group all sibling items with the same prefix into single items // also add sibling prefixes and suffixes and spaces in between var newItems = []; var prevItem = null; this.itemList.forEach(function(item) { if (prevItem) { if (item.level == prevItem.level && item.equalPrefix(prevItem)) { if (item.addSpace || prevItem.addSpace) { prevItem.textLines[prevItem.textLines.length - 1] += "
      "; } prevItem.textLines = prevItem.textLines.concat(item.textLines); } else { prevItem.addSiblingSuffix(); newItems.push(prevItem); item.addSiblingPrefix(); prevItem = item; } } else { item.addSiblingPrefix(); prevItem = item; } }); prevItem.addSiblingSuffix(); newItems.push(prevItem); this.itemList = newItems; } OutputGroup.prototype.getText = function() { // return a text string for all output if (this.itemList.length == 0) return ""; var lines = []; this.itemList.forEach(function(item) { lines = lines.concat(item.textLines); }); return lines.join("\n"); } window.onclick = function(event) { // handle mouse clicks for open/close and selection var spot; if (event.target.tagName == "SPAN") { var elemId = event.target.parentElement.getAttribute("id"); spot = spotDict[elemId]; if (spot) { if (event.target.classList.contains("marker")) { spot.toggleOpen(); } else if (event.target.classList.contains("nodetext")) { spot.select(); } } } else if (event.target.tagName == "A") { var addr = event.target.getAttribute("href"); if (addr.startsWith("#")) { event.preventDefault(); spot = spotDict[addr.substr(1)]; if (spot) { spot.openParents(); spot.select(); } } } } window.onkeydown = function(event) { // handle arrow keys for selection management var spot; switch (event.which) { case 38: // up arrow if (selectedSpot) { spot = selectedSpot.prevTreeSpot(); } else { spot = rootSpots[0]; } if (spot) spot.select(); event.preventDefault(); break; case 40: // down arrow if (selectedSpot) { spot = selectedSpot.nextTreeSpot(); } else { spot = rootSpots[0]; } if (spot) spot.select(); event.preventDefault(); break; case 37: // left arrow if (selectedSpot && selectedSpot.open) selectedSpot.toggleOpen(); event.preventDefault(); break; case 39: // right arrow if (selectedSpot && !selectedSpot.open) selectedSpot.toggleOpen(); event.preventDefault(); break; } } function valueOrDefault(object, name, dflt) { // return the value of the named property or the default value var value = object[name]; if (value !== undefined) return value; return dflt; } function escapeHtml(text) { // return the given string with &, <, > escaped return text.replace(/&/g, '&').replace(//g, '>'); } function unescapeHtml(text) { // return the given string with &, <, > unescaped return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); } function removeMarkup(text) { // return text with all HTML Markup removed and entities unescaped return text.replace(/<.*?>/g, "").replace(/&/g, "&"). replace(/</g, "<").replace(/>/g, ">"); } function formatNumber(num, format) { // return a formttted string for the given number var formatParts = format.split(/e/i); if (formatParts.length < 2) return formatBasicNumber(num, format); var formatMain = formatParts[0]; var formatExp = formatParts[1]; var exp = Math.floor(Math.log(Math.abs(num)) / Math.LN10); num = num / Math.pow(10, exp); var totalPlcs = (formatMain.match(/[#0]/g) || []).length; if (totalPlcs < 1) totalPlcs = 1; num = Number(num.toFixed(totalPlcs - 1)); var radix = "."; if (format.indexOf("\\,") < 0 && (format.indexOf("\\.") >= 0 || (format.indexOf(",") >= 0 && format.indexOf(".") < 0))) { radix = ","; } var formatWhole = formatMain.split(radix)[0]; var wholePlcs = (formatWhole.match(/[#0]/g) || []).length; var expChg = wholePlcs - Math.floor(Math.log(Math.abs(num)) / Math.LN10) - 1; num = num * Math.pow(10, expChg); exp -= expChg; var c = format.indexOf("e") >= 0 ? "e" : "E"; return formatBasicNumber(num, formatMain) + c + formatBasicNumber(exp, formatExp) } function formatBasicNumber(num, format) { // return a formatted string for the given number without an exponent var radix; if (format.indexOf("\\,") < 0 && (format.indexOf("\\.") >= 0 || (format.indexOf(",") >= 0 && format.indexOf(".") < 0))) { radix = ","; format.replace(/\\./g, "."); } else { radix = "."; format.replace(/\\,/g, ","); } var formatParts = format.split(radix); var formatWhole = formatParts[0].split(""); var formatFract = formatParts.length > 1 ? formatParts[1] : ""; var decPlcs = (formatFract.match(/[#0]/g) || []).length; formatFract = formatFract.split(""); var numParts = num.toFixed(decPlcs).split("."); var numWhole = numParts[0].split(""); var numFract = numParts.length > 1 ? numParts[1] : ""; numFract = numFract.replace(/0+$/g, "").split(""); var sign = "+"; if (numWhole[0] == "-") sign = numWhole.shift(); var c; var result = []; while (numWhole.length || formatWhole.length) { c = formatWhole.length ? formatWhole.pop() : ""; if (c && "#0 +-".indexOf(c) < 0) { if (numWhole.length || formatWhole.indexOf("0") >= 0) { result.unshift(c); } } else if (numWhole.length && c != " ") { result.unshift(numWhole.pop()); if (c && "+-".indexOf(c) >= 0) { formatWhole.push(c); } } else if ("0 ".indexOf(c) >= 0) { result.unshift(c); } else if ("+-".indexOf(c) >= 0) { if (sign == "-" || c == "+") { result.unshift(sign); } sign = ""; } } if (sign == "-") { if (result[0] == " ") { result = [result.join("").replace(/\s(?!\s)/, "-")]; } else { result.unshift("-"); } } if (formatFract.length || (format.length && format.charAt(format.length - 1) == radix)) { result.push(radix); } while (formatFract.length) { c = formatFract.shift(); if ("#0 ".indexOf(c) < 0) { if (numFract.length || formatFract.indexOf("0") >= 0) { result.push(c); } } else if (numFract.length) { result.push(numFract.shift()); } else if ("0 ".indexOf(c) >= 0) { result.push("0"); } } return result.join(""); } function initNumbering(format) { // return an array of basic numbering formats var sectionStyle = false; var tmpFormat = format.replace(/\.\./g, ".").replace(/\/\//g, "\0"); var delim = "/"; var formats = tmpFormat.split(delim); if (formats.length < 2) { tmpFormat = format.replace(/\/\//g, "/").replace(/\.\./g, "\0"); delim = "."; formats = tmpFormat.split(delim); if (formats.length > 1) sectionStyle = true; } formats = formats.map(function(text) { return new NumberingFormat(text.replace(/\0/g, delim), sectionStyle); }); return formats; } function NumberingFormat(formatStr, sectionStyle) { // class to store basic formatting for an element of numbering fields this.romanDict = {0: "", 1: "I", 2: "II", 3: "III", 4: "IV", 5: "V", 6: "VI", 7: "VII", 8: "VIII", 9: "IX", 10: "X", 20: "XX", 30: "XXX", 40: "XL", 50: "L", 60: "LX", 70: "LXX", 80: "LXXX", 90: "XC", 100: "C", 200: "CC", 300: "CCC", 400: "CD", 500: "D", 600: "DC", 700: "DCC", 800: "DCCC", 900: "CM", 1000: "M", 2000: "MM", 3000: "MMM"}; this.sectionStyle = sectionStyle; var match = /(.*)([1AaIi])(.*)/.exec(formatStr); if (match) { this.prefix = match[1]; this.format = match[2]; this.suffix = match[3]; } else { this.prefix = formatStr; this.format = "1"; this.suffix = ""; } } NumberingFormat.prototype.numString = function(num) { var result = ""; var digit; var factor = 1000; if (num > 0) { if (this.format == "1") { result = num.toString(); } else if (this.format == "A" || this.format == "a") { while (num) { digit = (num - 1) % 26; result = String.fromCharCode(digit + "A".charCodeAt(0)) + result; num = Math.floor((num - digit - 1) / 26); } if (this.format == "a") result = result.toLowerCase(); } else if (num < 4000) { while (num) { digit = num - (num % factor); result += this.romanDict[digit]; factor = Math.floor(factor / 10); num -= digit; } if (this.format == "i") result = result.toLowerCase(); } } return this.prefix + result + this.suffix; } function formatNumbering(value, numFormats) { // return a formatted string for a numbering field var inputNums = value.split(".").map(function(num) { return Number(num); }); if (numFormats[0].sectionStyle) { numFormats = numFormats.slice(); while (numFormats.length < inputNums.length) { numFormats.push(numFormats[numFormats.length - 1]); } var results = inputNums.map(function(num, i) { return numFormats[i].numString(num); }); return results.join("."); } else { var numFormat = numFormats[inputNums.length - 1]; if (!numFormat) numFormat = numFormats[numFormats.length - 1]; return numFormat.numString(inputNums[inputNums.length - 1]); } } function formatDate(storedText, format) { // return a formatted date string var monthNames = ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; var dateArray = storedText.split("-"); var year = dateArray[0]; var month = dateArray[1]; var day = dateArray[2]; var yearNum = Number(year); var monthNum = Number(month); var dayNum = Number(day); format = format.replace(/%-d/g, dayNum).replace(/%d/g, day); format = format.replace(/%a/g, weekday(yearNum, monthNum, dayNum).substr(0, 3)); format = format.replace(/%A/g, weekday(yearNum, monthNum, dayNum)); format = format.replace(/%-m/g, monthNum).replace(/%m/g, month); format = format.replace(/%b/g, monthNames[monthNum].substr(0, 3)); format = format.replace(/%B/g, monthNames[monthNum]); format = format.replace(/%y/g, year.slice(-2)).replace(/%Y/g, year); format = format.replace(/%-U/g, weekNumber(yearNum, monthNum, dayNum)); format = format.replace(/%-j/g, dayOfYear(yearNum, monthNum, dayNum)); return format; } function dayOfYear(year, month, day) { // return the day of year (1 to 366) var daysInMonths = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334]; var day = daysInMonths[month - 1] + day; if (month > 2 && year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) { day += 1; } return day; } function firstWeekday(year) { // return a number for the weekday of Jan. 1st (0=Sun., 6=Sat.) var y = year - 1; return (y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) + 1) % 7; } function weekday(year, month, day) { // return the weekday name for the given date var weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; var day = (firstWeekday(year) + dayOfYear(year, month, day) - 1) % 7; return weekdays[day]; } function weekNumber(year, month, day) { // return the week number for the given date return Math.floor((dayOfYear(year, month, day) + firstWeekday(year) - 1) / 7); } function formatTime(storedText, format) { // return a formatted time string var timeArray = storedText.split(":"); var hour = timeArray[0]; var minute = timeArray[1]; var second = timeArray[2].split(".")[0]; var microSecond = timeArray[2].split(".")[1]; var hourNum = Number(hour); var minuteNum = Number(minute); var secondNum = Number(second); format = format.replace(/%-H/g, hourNum).replace(/%H/g, hour); var ampm = "AM"; if (hourNum == 0) { hourNum = 12; hour = "12"; } else if (hourNum > 11) { ampm = "PM"; if (hourNum > 12) { hourNum -= 12; hour = hourNum.toString(); if (hourNum < 10) hour = "0" + hour; } } format = format.replace(/%-I/g, hourNum).replace(/%I/g, hour); format = format.replace(/%-M/g, minuteNum).replace(/%M/g, minute); format = format.replace(/%-S/g, secondNum).replace(/%S/g, second); format = format.replace(/%f/g, microSecond).replace(/%p/g, ampm); return format; } function formatBoolean(storedText, format) { // return a formatted boolean string var boolDict = {"true": 0, "false": 1, "t": 0, "f": 1, "yes": 0, "no": 1, "y": 0, "n": 1}; var valueNum = boolDict[storedText.toLowerCase()]; var value = format.split("/")[valueNum]; if (value == undefined) value = "#####"; return value; } main(); TreeLine-3.2.1/translations/000077500000000000000000000000001506556630100157545ustar00rootroot00000000000000TreeLine-3.2.1/translations/qt_de.qm000066400000000000000000000656031506556630100174210ustar00rootroot00000000000000ʴ5>4 Ac>} K!?> bb?( b`? la@ la@8 lf@n t@ @ A ˰BU B %'C- C )D */D9 =Dr BD T^EU c(E eE JE %pF ,Fa F ˔F :G f GO sG G 0NH E9H Mc\I* f)Ir I 5TKa HK $K .@L iLO L L JMF ̺M -DM kN 0NZ N .N RVOC RVO| SO YO [P j7oP pQ\ Q R R %S( Si +>S ;ɾS PtT ^+dTK feT gT iFCU iU uU wV1 w}V ^V RW t5W WpSX XRuXGa.XYY>ݖY[yZ  Z`%4Z-vZ0i)[[0[2wT[a\c5\{~a\`]5]N]ky^J_0P_t2_i`J**QWidget++ QShortcutAMAM QDateTimeEditOKOK QColorDialogOKOKQDialogButtonBoxOKOK QMessageBoxOKOK QPrintDialogOKOKQPrintPropertiesDialogPMPM QDateTimeEditNeinNo QShortcutHochUp QShortcutamam QDateTimeEditpmpm QDateTimeEditto QPrintDialog&OK&OK QErrorMessage N&ein&NoQDialogButtonBoxAltAlt QShortcutF%1F%1 QShortcutEntfDel QShortcutEndeEnd QShortcutEscEsc QShortcut EinfgIns QShortcutTabTab QShortcut AnfangTop QScrollBarXIMXIM QInputContextJaYes QShortcutFehler: Fatal Error: QErrorMessage&Ja&YesQDialogButtonBox ZurckBack QFileDialog ZurckBack QShortcut AnrufCall QShortcut&AusschneidenCu&t QLineEdit&AusschneidenCu&t QTextControlStrgCtrl QShortcut RunterDown QShortcutBeendenExitQMenuBar DateiFile QFileDialog DateiFile QPrintDialogUmdrehenFlip QShortcut HilfeHelpQDialogButtonBox HilfeHelp QMessageBox HilfeHelp QShortcutPos1HomeQObjectPos1Home QShortcutKind QDirModel LinksLeft QShortcutMenMenu QShortcutMetaMeta QShortcutNameNamePPDOptionsModelNameName QDirModel ffnenOpenQDialogButtonBox ffnenOpen QFileDialogBild aufwrtsPgUp QShortcut WiederherstellenRedo QUndoGroup WiederherstellenRedo QUndoStackBeendenQuitQMenuBarSpeichernSaveQDialogButtonBoxSpeichernSaveQPrintPropertiesDialog GreSize QDirModelSortierenSort QFileDialogAbbrechenStop QShortcutWahrTrueQObjectRckgngigUndo QUndoGroupRckgngigUndo QUndoStack"A6 (105 x 148 mm)A6 (105 x 148 mm) QPrintDialog&Kopieren&Copy QLineEdit&Kopieren&Copy QTextControl&Schriftart&Font QFontDialogVer&schieben&Move QWorkspace&ffnen&Open QFileDialog &Rot:&Red: QColorDialog"Wieder&herstellen&Redo QLineEdit"Wieder&herstellen&Redo QTextControl &Sat:&Sat: QColorDialogS&peichern&Save QFileDialog &Gre&Size QFontDialog&Gre ndern&Size QWorkspace&Rckgngig&Undo QLineEdit&Rckgngig&Undo QTextControl &Val:&Val: QColorDialogFLegal (8,5 x 14 Zoll, 216 x 356 mm)%Legal (8.5 x 14 inches, 216 x 356 mm) QPrintDialogAbbrechenAbortQDialogButtonBoxberAboutQMenuBarAnwendenApplyQDialogButtonBoxSchlieenCloseQDialogButtonBoxSchlieenClose QWorkspaceLaufwerkDrive QFileDialog EnterEnter QShortcut FalschFalseQObjectFarb&ton:Hu&e: QColorDialogMinimierenMinimize QWorkspaceAlles drucken Print all QPrintDialog ffnenOpen  QFileDialog PausePause QShortcutSonstigesOther QPrintDialog DruckPrint QPrintDialog DruckPrint QShortcutResetQDialogButtonBoxWiederholenRetryQDialogButtonBox RechtsRight QShortcutEinrichtenSetupQMenuBarUmschaltShift QShortcutSize: QPrintDialogLeertasteSpace QShortcutValuePPDOptionsModelDirekthilfe What's This?QDialogDirekthilfe What's This?QWhatsThisAction

      About Qt

      %1

      Qt is a C++ toolkit for cross-platform application development.

      Qt provides single-source portability across MS Windows, Mac OS X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.

      Qt is a Trolltech product. See www.trolltech.com/qt/ for more information.

       QMessageBoxRestore DefaultsQDialogButtonBoxAufzeichnen Media Record QShortcut"B6 (125 x 176 mm)B6 (125 x 176 mm) QPrintDialog$Bildschirm drucken Print Screen QShortcut8Eigene Farben &definieren >>&Define Custom Colors >> QColorDialogPapierquelle: Paper source: QPrintDialogB8 (62 x 88 mm)B8 (62 x 88 mm) QPrintDialogA8 (52 x 74 mm)A8 (52 x 74 mm) QPrintDialogB9 (44 x 62 mm)B9 (44 x 62 mm) QPrintDialogA9 (37 x 52 mm)A9 (37 x 52 mm) QPrintDialog*Nach &Gre sortieren Sort by &Size QFileDialog&B0 (1000 x 1414 mm)B0 (1000 x 1414 mm) QPrintDialog*Nach &Datum sortieren Sort by &Date QFileDialog(Nach &Name sortieren Sort by &Name QFileDialog9'%1' is write protected. Do you want to delete it anyway? QFileDialogDAktiviert das Programmhauptfenster#Activates the program's main window QApplicationShow Details... QMessageBox"A5 (148 x 210 mm)A5 (148 x 210 mm) QPrintDialog,Tabloid (279 x 432 mm)Tabloid (279 x 432 mm) QPrintDialogHRLE Start of right-to-left embedding$RLE Start of right-to-left embeddingQUnicodeControlCharacterMenu.Im &Vordergrund bleiben Stay on &Top QWorkspaceJDiese Meldungen noch einmal an&zeigen&Show this message again QErrorMessage B10 (31 x 44 mm)B10 (31 x 44 mm) QPrintDialog,Windows-EingabemethodeWindows input method QInputContext&Dekrementieren Step &downQAbstractSpinBoxHhen - Treble Down QShortcut$XIM-EingabemethodeXIM input method QInputContext"B2 (500 x 707 mm)B2 (500 x 707 mm) QPrintDialogSchl&ieen&Close QWorkspacePPD PropertiesQPrintPropertiesDialogEinf&gen&Paste QLineEditEinf&gen&Paste QTextControl Selection QPrintDialog*Rollen-Feststelltaste Scroll Lock QShortcut&Nach unten scrollen Scroll down QScrollBarHier scrollen Scroll here QScrollBar&Nach links scrollen Scroll left QScrollBar QUndoModel"A3 (297 x 420 mm)A3 (297 x 420 mm) QPrintDialog*Die Selektion DruckenPrint selection QPrintDialog%1 - [%2] %1 - [%2] QWorkspace*ZWSP Zero width spaceZWSP Zero width spaceQUnicodeControlCharacterMenuLautstrke - Volume Down QShortcutTon aus Volume Mute QShortcut"B4 (250 x 353 mm)B4 (250 x 353 mm) QPrintDialogVorherigerMedia Previous QShortcut Home Page QShortcutPapierformat Paper format QPrintDialogLautstrke + Volume Up QShortcut Print dialog QPrintDialog/%1 already exists. Do you want to overwrite it? QPrintDialog"A1 (594 x 841 mm)A1 (594 x 841 mm) QPrintDialogFarbauswahl Select color QColorDialog Printer info: QPrintDialogRZu benutzerdefinierten Farben &hinzufgen&Add to Custom Colors QColorDialog Bla&u:Bl&ue: QColorDialogLTRQT_LAYOUT_DIRECTION QApplicationEndeBottom QScrollBarAbbrechenCancel QColorDialogAbbrechenCancelQDialogButtonBoxAbbrechenCancel QPrintDialogAbbrechenCancelQProgressDialogBrowse QPrintDialogStart (6) Launch (6) QShortcutStart (7) Launch (7) QShortcutStart (8) Launch (8) QShortcutStart (9) Launch (9) QShortcutStart (2) Launch (2) QShortcutStart (3) Launch (3) QShortcutStart (4) Launch (4) QShortcutStart (5) Launch (5) QShortcutStart (0) Launch (0) QShortcutStart (1) Launch (1) QShortcutStart (F) Launch (F) QShortcutStart (B) Launch (B) QShortcutStart (C) Launch (C) QShortcutStart (D) Launch (D) QShortcutStart (E) Launch (E) QShortcutStart (A) Launch (A) QShortcutKonfigurationConfigQMenuBarCopies QPrintDialogLschenDelete QLineEditLschenDelete QShortcutLschenDelete QTextControlQuerformat Landscape QPrintDialog EscapeEscape QShortcutAuflegenHangup QShortcut"ElternverzeichnisParent Directory QFileDialog$B1 (707 x 1000 mm)B1 (707 x 1000 mm) QPrintDialog> File not found. Please verify the correct file name was given QFileDialogIgnorierenIgnoreQDialogButtonBoxEinfgenInsert QShortcut(Folio (210 x 330 mm)Folio (210 x 330 mm) QPrintDialogBass Boost Bass Boost QShortcutBild abwrtsPgDown QShortcut$DLE (110 x 220 mm)DLE (110 x 220 mm) QPrintDialog ReturnReturn QShortcutBeispielSample QFontDialog&AufrollenSh&ade QWorkspace SuchenSearch QShortcutAuswhlenSelect QShortcut&Unsortiert &Unsorted QFileDialog$C5E (163 x 229 mm)C5E (163 x 229 mm) QPrintDialog"B5 (176 x 250 mm)%B5 (176 x 250 mm, 6.93 x 9.84 inches) QPrintDialog SysReqSysReq QShortcut*Zahlen-FeststelltasteNumLock QShortcutMein Computer My Computer QFileDialogBereich drucken Print range QPrintDialog*Rollen-Feststelltaste ScrollLock QShortcutClose without SavingQDialogButtonBoxKontext1Context1 QShortcutKontext2Context2 QShortcutKontext3Context3 QShortcutKontext4Context4 QShortcutSuchen in:Look in: QFileDialog$Anzahl der Kopien:Number of copies: QPrintDialogOptionenOptionsQMenuBarBild aufwrtsPage Up QShortcut(Eine Seite nach obenPage up QScrollBar File exists QPrintDialog.Mac OS X-EingabemethodeMac OS X input method QInputContextHochformatPortrait QPrintDialogffne URLOpen URL QShortcut Properties QPrintDialogDebug Ausgabe:Debug Message: QErrorMessageFeststelltaste Caps Lock QShortcutDateiname: File name: QFileDialogSeitengre: Page size: QPrintDialog,Eine Seite nach rechts Page right QScrollBarDruckerPrinter QPrintDialogN&ein zu allem N&o to AllQDialogButtonBoxDouble side printing QPrintDialog$A0 (841 x 1189 mm)A0 (841 x 1189 mm) QPrintDialogSchrifts&til Font st&yle QFontDialog8Farbig drucken falls mglichPrint in color if available QPrintDialog direkt verbundenlocally connected QPrintDialog*Ledger (432 x 279 mm)Ledger (432 x 279 mm) QPrintDialog"Dateien des Typs:Files of type: QFileDialogSystem RequestSystem Request QShortcutFeststelltasteCapsLock QShortcutRck-TabBacktab QShortcut Bass +Bass Up QShortcutWarnung:Warning: QErrorMessage&SchriftsystemWr&iting System QFontDialogAktualisierenRefresh QShortcutQuit %1QMenuBarSave AllQDialogButtonBox"Wieder&herstellen&Restore QWorkspace8&Versteckte Dateien anzeigenShow &hidden files QFileDialog!Are sure you want to delete '%1'? QFileDialog@Unicode-Kontrollzeichen einfgen Insert Unicode control characterQUnicodeControlCharacterMenu$Nach oben scrollen Scroll up QScrollBarber QtAbout QtQMenuBarber QtAbout Qt QMessageBoxAbout %1QMenuBarSpeichern unterSave As QFileDialogAlias: %1 Aliases: %1 QPrintDialog%1 Das Verzeichnis konnte nicht gefunden werden. Stellen Sie sicher, dass der Verzeichnisname richtig ist.K%1 Directory not found. Please verify the correct directory name was given. QFileDialogEinstellungenSettingQMenuBarFLRO Start of left-to-right override#LRO Start of left-to-right overrideQUnicodeControlCharacterMenuHLRE Start of left-to-right embedding$LRE Start of left-to-right embeddingQUnicodeControlCharacterMenuStart Mail Launch Mail QShortcutPrint To File ... QPrintDialogRcktaste Backspace QShortcut(Schriftart auswhlen Select Font QFontDialogJUS Common #10 Envelope (105 x 241 mm)%US Common #10 Envelope (105 x 241 mm) QPrintDialog Bass - Bass Down QShortcutCollate QPrintDialog Liste List View QFileDialogStandbyStandby QShortcut&Inkrementieren&Step upQAbstractSpinBox&Lschen&Delete QFileDialogAktivierenActivate QApplication&Unterstrichen &Underline QFontDialog &Grn:&Green: QColorDialog Alle Dateien (*) All Files (*) QFileDialogVerzeichnisse Directories QFileDialogDiscardQDialogButtonBoxjApplikation '%1' bentigt Qt %2, aber Qt %3 gefunden.,Executable '%1' requires Qt %2, found Qt %3. QApplication4Whlen Sie ein VerzeichnisSelect a Directory QFileDialogJa zu &allem Yes to &AllQDialogButtonBox$Alle Dateien (*.*)All Files (*.*) QFileDialog|

      This program uses Qt Open Source Edition version %1.

      Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.

      Please see www.trolltech.com/company/model/ for an overview of Qt licensing.

       QMessageBoxErne&ut laden&Reload QFileDialog&Umbenennen&Rename QFileDialogCould not delete directory. QFileDialogHhen + Treble Up QShortcut"A4 (210 x 297 mm)%A4 (210 x 297 mm, 8.26 x 11.7 inches) QPrintDialogAlles auswhlen Select All QLineEditAlles auswhlen Select All QTextControlVerzeichnis: Directory: QFileDialogEffekteEffects QFontDialog Durch&gestrichen Stri&keout QFontDialog(Nach rechts scrollen Scroll right QScrollBar*Zahlen-FeststelltasteNum Lock QShortcut*Zahlen-Feststelltaste Number Lock QShortcutGrundfar&ben &Basic colors QColorDialogUnbekanntUnknown QFileDialogunbekanntunknown QPrintDialog Pages from QPrintDialog&Herabrollen&Unshade QWorkspace,RLM Right-to-left markRLM Right-to-left markQUnicodeControlCharacterMenu|Die Datei %1 existiert bereits. Soll sie berschreiben werden?-%1 already exists. Do you want to replace it? QFileDialog4&Benutzerdefinierte Farben&Custom colors QColorDialog%Do you want to overwrite it? QPrintDialogNExecutive (7,5 x 10 Zoll, 191 x 254 mm))Executive (7.5 x 10 inches, 191 x 254 mm) QPrintDialog<PDF Pop directional formattingPDF Pop directional formattingQUnicodeControlCharacterMenuEinstellungen PreferenceQMenuBar PreferencesQMenuBarA&lphakanal:A&lpha channel: QColorDialogCopy &Link Location QTextControlM&inimieren Mi&nimize QWorkspace6Letzte Seite zuerst druckenPrint last page first QPrintDialogLinke Seite Left edge QScrollBarHLetter (8,5 x 11 Zoll, 216 x 279 mm)&Letter (8.5 x 11 inches, 216 x 279 mm) QPrintDialogFavoriten Favorites QShortcutVorwrtsForward QShortcutBild abwrts Page Down QShortcut*Eine Seite nach unten Page down QScrollBar*Eine Seite nach links Page left QScrollBarHide Details... QMessageBox4ZWNJ Zero width non-joinerZWNJ Zero width non-joinerQUnicodeControlCharacterMenuMa&ximieren Ma&ximize QWorkspace Wiederherstellen Restore Down QWorkspaceTypAll other platformsType QDirModelFRLO Start of right-to-left override#RLO Start of right-to-left overrideQUnicodeControlCharacterMenu Don't SaveQDialogButtonBox Print to file QPrintDialog*ZWJ Zero width joinerZWJ Zero width joinerQUnicodeControlCharacterMenu=File %1 is not writable. Please choose a different file name. QPrintDialog"B3 (353 x 500 mm)B3 (353 x 500 mm) QPrintDialog,Neuen Ordner erstellenCreate New Folder QFileDialog Date Modified QDirModel,LRM Left-to-right markLRM Left-to-right markQUnicodeControlCharacterMenuWiedergabe Media Play QShortcut Stopp Media Stop QShortcutNchster Media Next QShortcut^<p>Dieses Programm verwendet Qt Version %1.</p>'

      This program uses Qt version %1.

       QMessageBoxRechte Seite Right edge QScrollBar$Start Media Player Launch Media QShortcut A7 (74 x 105 mm)A7 (74 x 105 mm) QPrintDialogDetails Detail View QFileDialog%1 Die Datei konnte nicht gefunden werden. Stellen Sie sicher, dass der Dateiname richtig ist.A%1 File not found. Please verify the correct file name was given. QFileDialog"A2 (420 x 594 mm)A2 (420 x 594 mm) QPrintDialog"Druckausrichtung: Orientation: QPrintDialog B7 (88 x 125 mm)B7 (88 x 125 mm) QPrintDialog<Qt Bibliothek ist inkompatibelIncompatible Qt Library Error QApplicationTreeLine-3.2.1/translations/qt_es.qm000066400000000000000000001024551506556630100174350ustar00rootroot00000000000000;`;;;;M OO-7}ImS](5c+;o+;+O+OH4HJKLDLPSZr+[`7\O_[_s1}-,CUx%%%%90M0m005 D+,Y RZ ^Zg d\]4 x\ |^ vv@`f߮IA[Iyɵnɵnɵnɵn3ɵnJɵn`ɵny B1 YMqH<po5#Q%UT*42C'CdCCeCeD"!D"^D1MaR?4fP:l^oRdw^|{yW2j. d0yi6ur< B"lH)-/=N1$5~ < d?NNkyT]|``) 6s^= &,fE{8AA [ynL ME*E_ww!e)*/e52;8ByOZf` Bcփ Hu( jl p v$ |$ !!(!^!ֈ7"n n"t,"z";y"""&H"/"IxS"YM#>YM#yh^#i#ssc$=w$C$I$ۊ$N$]$I$I$I%%I%KI%rI%I%I%I&n&*I&0Y&Ji&dy&~&&&&''I'4'N'h'''uD'uD( o(A,(G,(i,(,(,((ɘe(5$(fR)N)6)Nc)z*^*,Pq*2V*~*** **+&%C+,?"+LKN+RM+XR+]+]+k+y^+{y++G%+ǥ,,++,At,]t,{y,r,-(-:%-@C--F5-ƨ-ƨ-˾-ҝz-է?.f.6~b.to.!.+3./.6 /G/4LAU/~U/U/Z/Z/Z0Z0&]k*0>^n0Xe0i0i1rg19y;1a}u1g}w1}w122@t2zt2.2.2P2D3 t3t3t3_ 4%F4=ʢ4Cʢ4Xd4^d4sd4d4594֣44U4B5w5E 5K25Q65D5K6U|6/ar6_p6et6}wZ6}$6}$7Z7LK<7R7l7 7/7E8,@58du8T8i~99h5kE9XU 9bD9gA:i$:nx1 :tz*2:d:U:5:z:҉;m;n;8;\O~;vC;|ʴ5;Ԅ;D<d<F5="Y=(I=.As=b =z }$= qe= ڤ= E>. E>E Ac>K Ac> 35> K!?? bb? b`?l i3? la@ |@6 t@ t@ @ @ A A >A A A B KB B %'Bb B C> C^ )Cd */Cj 7uC| =C BC T^D2 ]DX `D `D c(D dD eD eE f1E& gEj gnE k,F rD"F( xFp ~Fv F| 9F IF IG! ;G9 Ge G| JG %pG ,G ,G G ˔G PH H+ Hd 68H :H f H f I5 4Ig sIm sI AAI J m,J #-tJX 0NJ E9K& E9Ko LK Mc\K SK VK ]$L/ f)L5 f)L| io>L m`M wM 5TM< HMT HM $M .@M M iN Na N N JN JO t.O9 kO? ӇOE OK ̺Ow -DO kO U)O <P 0P  P-  Pd P xHP .P 7FQ >QP >Q >Q >Q >R$ >RZ DTR IR RVR RVR S.S SSN YST [Sv j7oS pT .T< BTB TH TT TT TT TT T T T )dU0 U .U .U .U .V aV yVW V] Vc tV :bV ʜW+ DW1  rW7 +>W 0EW ;ɾX PtX ^+dX feY- gYQ iFCY iY uY wY wZ8 w}Zj w}Z Z [ ^[> R[D o[~ X[ D[ t5\ \( )\L \T\gT\pS\*\/E\I_]$XRu][ ]a.^PvɅ^Vy$^p~^^S^B_V__ݖ`[y`  `H `"#`$U`%4a-va 0i)a?0ak1ca2wTaDaHbqJdbL$.bacc5cyCd{~ad`ddeNe(kyeJePft2f.fvffif*+AMAceptar Q3TabDialogAceptar QAxSelectAceptar QColorDialogAceptarQDialogButtonBoxAceptar QMessageBoxAceptar QPrintDialogAceptarPMNo QShortcutNo Arribaampm%1%&Aceptar Q3FileDialog&Aceptar&No Q3FileDialog&NoAltF%1SuprDirFinEscInsTabPrincipioXIMS QShortcutSError fatal:&S Q3FileDialog&S,Precedente (histrico) Q3FileDialogAnterior QFileDialogAnterior LlamarCor&tar Q3TextEditCor&tar QLineEditCor&tar FechaCtrl AbajoFichero Q3FileDialogFichero QFileDialogFicheroVoltear Ayuda Q3TabDialog AyudaQDialogButtonBox Ayuda QMessageBox Ayuda InicioIzquierdaMenMeta NombrePPDOptionsModel Nombre Q3FileDialog Nombre Abrir Q3FileDialog Abrir QComboBox AbrirQDialogButtonBox Abrir QFileDialog AbrirQMenu Abrir QPushButton Abrir Re Pg QUndoGroupGuardarQDialogButtonBoxGuardar QFileDialogGuardar Tamao Q3FileDialog TamaoOrdenar Q3FileDialogOrdenarDetenerVerdadero Q3DataTableVerdaderoTipo QUndoGroup"A6 (105 x 148 mm)&Copiar Q3TextEdit&Copiar QLineEdit&Copiar&Tipo de letra &Ayuda &Mover &Abrir Q3FileDialog &Abrir &Rojo:&Rehacer Q3TextEdit&Rehacer QLineEdit&Rehacer&Saturacin:&Guardar Q3FileDialog&Guardar&Tamao QFontDialog&Tamao&Deshacer Q3TextEdit&Deshacer QLineEdit&Deshacer&Brillo:NLegal (8,5 x 14 pulgadas, 216 x 356 mm)InterrumpirAplicar Q3TabDialogAplicar QCheckBoxLimpiar Cerrar Q3TitleBar CerrarQDialogButtonBox CerrarQMenu Cerrar Unidad Intro Falso Q3DataTable Falso Error &Tono:Minimizar Q3TitleBarMinimizar0No se ha podido abrir %1Imprimir todo Abrir  Q3FileDialog Abrir  PausaImpr Pant QPrintDialogImpr PantReintentarDerechaMayEspacio>La operacin de red ha expiradoLEl equpo remoto ha cerrado la conexinQu es esto?QDialogQu es esto?ZEl protocolo %1 no permite recibir ficherosPEl listado del directorio ha fallado: %1bNo se ha podido borrar el fichero o directorio %1Escritura: %1Grabar medio"B6 (125 x 176 mm) QDB2Driver QIBaseDriver QIBaseResult QMYSQLDriver QODBCDriverQSQLite2Driver(Equipo no encontradoQAbstractSocket(Equipo no encontrado<Descriptor de socket no vlido"Imprimir pantallaD&Definir colores personalizados >>"Fuente del papel:B8 (62 x 88 mm)treferencia a entidad no analizada en un contexto no vlidoA8 (52 x 74 mm)B9 (44 x 62 mm):Tipo de protocolo no admitidoA9 (37 x 52 mm)&Ordenar por &tamao Q3FileDialog&Ordenar por &tamao&B0 (1000 x 1414 mm)$Ordenar por &fecha Q3FileDialog$Ordenar por &fecha&Ordenar por &nombre Q3FileDialog&Ordenar por &nombreRFallo de la creacin de un directorio: %1LNo se ha podido crear el directorio %1Nueva carpeta 1PActiva la ventana principal del programa"A5 (148 x 210 mm).Tabloide (279 x 432 mm)HRLE Start of right-to-left embedding6Permanecer en &primer plano<Mo&strar este mensaje de nuevoBsintaxis no vlida para lookaheadno se permiten referencias a entidades externas generales ya analizadas en la DTD B10 (31 x 44 mm)2Mtodo de entrada Windows^valor errneo para la declaracin independienteRe&ducirNo conectado Bajar los agudosRConexin para conexin de datos rechazada*Mtodo de entrada XIMse esperaba una declaracin de codificacin o declaracin autnoma al leer la declaracin XML"B2 (500 x 707 mm)el directorio QDB2Result"&Tipo de fichero:&&Nombre de fichero:bNo hay ningn fichero o directorio con ese nombre&Cerrar4Identificacin fallida: %1 &Pegar Q3TextEdit &Pegar QLineEdit &Pegar4Bloqueo del desplazamiento*Desplazar hacia abajo(Desplazar hasta aqu8Desplazar hacia la izquierdaBorrar %1HFallo de la descarga del fichero: %1"A3 (297 x 420 mm) QDB2Result QMYSQLResult QOCIResult QODBCResultQSQLite2Result%1 - [%2]&Conectado al equipoQFtp&Conectado al equipoAlinear Q3MainWindowAlinear*ZWSP Zero width space Bajar el volumenSilenciarIntento de usar un socket IPv6 sobre una plataforma que no contempla IPv6"B4 (250 x 353 mm)>La plataforma no contempla IPv6Medio anterior>no se ha producido ningn errorQRegExp>no se ha producido ningn error|se ha producido un error durante el anlisis de una referencia"Formato del papel Subir el volumense esperaba una declaracin independiente al leer la declaracin XML"A1 (594 x 841 mm)*Seleccin de un colorH&Aadir a los colores personalizados,Conectado al equipo %1QFtp,Conectado al equipo %1 Ms...zEl protocolo %1 no permite renombrar ficheros o directoriosPLa conexin con el equipo ha fallado: %1 Az&ul:LTR FinalCancelar Q3FileDialogCancelarQ3ProgressDialogCancelar Q3TabDialogCancelar QColorDialogCancelarQDialogButtonBoxCancelar QFileDialogCancelar QPrintDialogCancelarQProgressDialogCancelarLanzar (6)Lanzar (7)Lanzar (8)Lanzar (9)Lanzar (2)Lanzar (3)Lanzar (4)Lanzar (5)Lanzar (0)Lanzar (1)Lanzar (F)Lanzar (B)Lanzar (C)Lanzar (D)Lanzar (E)Lanzar (A).Equipo %1 no encontradoQFtp.Equipo %1 no encontrado Borrar Q3DataTable Borrar QLineEdit Borrar QShortcut BorrarQSql BorrarApaisado EscapeR&ecargarNueva carpetaDescolgar&Directorio superiorEl protocolo %1 no permite listar los ficheros de un directorio$B1 (707 x 1000 mm)FEl envo del fichero ha fallado: %1IgnorarInsertar Q3DataTableInsertar QShortcutInsertar(Folio (210 x 330 mm)(desconocido)(Potenciar los graves QIBaseDriver Av Pg$DLE (110 x 220 mm)RetornoMuestraSombre&arBsquedaSeleccionar&Sin ordenar Q3FileDialog&Sin ordenar$C5E (163 x 229 mm)NB5 (176 x 250 mm, 6,93 x 9,84 pulgadas) PetSis<falta el delimitador izquierdoBloq NumActualizar Q3DataTableActualizarBuscar &en:,Borrar este registro?8Imposible recibir un mensajeMi computadoraHContenido del fichero previsualizado$Imprimir intervaloBloq DesplDFallo del cambio de directorio: %1 Permiso denegado QIODevice Permiso denegadoContexto1Contexto2Contexto3Contexto4Buscar en:\nombre de instruccin de tratamiento no vlido Nueva carpeta %1"Equipo encontradoQFtp"Equipo encontrado"Nmero de copias:"Retroceder pgina.Una pgina hacia arriba QScrollBar.Una pgina hacia arriba4error debido al consumidor4Mtodo de entrada Mac OS XVertical QScrollBarVsintaxis no vlida para clase de caracteresvse ha producido un error durante el anlisis de un elemento$Conexin rechazadaQAbstractSocket$Conexin rechazadaQHttp$Conexin rechazadaAbrir URL QDB2Result QDB2Result QMYSQLResult QOCIResult8Guardar las modificaciones?$Imposible escribir&carcter inesperado,Mensaje de depuracin:JEliminacin de directorio fallida: %1.etiqueta desequilibrada"Lectura-escritura*Bloqueo de maysculas$Nombre de fichero:Slo lectura"Tamao de pgina:.Una pgina a la derecha QScrollBar.Una pgina a la derechaN&o a todoXse ha usado una caracterstica no habilitada$A0 (841 x 1189 mm),Solicitud HTTP fallida2&Estilo del tipo de letra>Imprimir en color si es posible2Copiar o mover un fichero(conectado localmenteT<qt>Seguro que desea borrar %1 %2?</qt>*Ledger (432 x 279 mm)*valor octal no vlido"Ficheros de tipo:(Peticin del sistemaJNo se ha podido leer el directorio %1Bloq Mays*Tabulador hacia atrs Subir los graves Aviso:*Sistema de escr&ituraPersonalizar...Actualizar&Restaurartse ha producido un error durante el anlisis del contenidozse ha producido un error durante el anlisis de un comentariono se permiten referencias a entidades internas generales en la DTD.Buscar en el directorioAtributos:Direccin de tipo desconocidobYa hay otro socket escuchando por el mismo puerto QMYSQLResult:Mostrar los ficheros &ocultos Q3FileDialog:Mostrar los ficheros &ocultos6Imposible enviar un mensajeHInsertar carcter de control Unicode,Desplazar hacia arribatEl protocolo %1 no permite borrar ficheros o directoriosAcerca de QtHLa direccin enlazada ya est en usoGuardar como Q3FileDialogGuardar comoAlias: %1%1 Directorio no encontrado. Verique que el nombre del directorio es correcto."Conexin expiradaError de redInaccesible QIBaseResultFLRO Start of left-to-right overrideHLRE Start of left-to-right embedding%1 Fichero no encontrado. Compruebe la ruta y el nombre del fichero.Lanzar correo Borrar(entidades recursivas8Seleccionar un tipo de letraDSobre US Common #10 (105 x 241 mm) Bajar los graves8Operacin socker no admitida QIBaseDriverConfirmarVista de lista Q3FileDialogVista de lista>Conexin rechazada al equipo %18Operacin socket no admitidaTms de una definicin de tipo de documento Fichero especialBOperacin detenida por el usuarioXEl protocolo %1 no permite enviar ficherosSlo escritura&CancelarQ3Wizard&Cancelar&el enlace simblico QMYSQLResult Reposo&Aumentar&Borrar Q3FileDialog&BorrarActivarS&ubrayado&Terminar*Conexin a %1 cerradaQFtp*Conexin a %1 cerradaDsintaxis no vlida para repeticin&Verde:,Todos los ficheros (*) Q3FileDialog,Todos los ficheros (*)Directorios Q3FileDialogDirectoriosDEliminacin de fichero fallida: %1LEnlace simblico a un fichero especialVImposible inicializar el socket de difusinlEl ejecutable %1 requiere Qt %2 (se encontr Qt %3).2Seleccionar un directorio Q3FileDialog2Seleccionar un directorioSiguie&nte >S a &todoDNo queda espacio en el dispositivo0Todos los ficheros (*.*) Q3FileDialog0Todos los ficheros (*.*)bse esperaba la versin al leer la declaracin XMLLectura: %1&Recargar&Renombrar Q3FileDialog&Renombrar Subir los agudosBNo se ha podido renombrar %1 a %2NA4 (210 x 297 mm, 8,26 x 11,7 pulgadas) Seleccionar todo Q3TextEdit Seleccionar todo QLineEdit Seleccionar todoDirectorio: Q3FileDialogDirectorio:&Valores por omisinEfectos&Tachado4Desplazar hacia la derecha0Fragmento HTTP no vlidoBloq num(Equipo %1 encontradoQFtp(Equipo %1 encontrado Bloqueo numrico<Longitud del contenido errnea Colores &bsicos*se esperaba una letra"Error desconocidoQFtp"Error desconocido QHostInfo"Error desconocidoQHostInfoAgent"Error desconocidoQHttp"Error desconocido QIODevice"Error desconocidoHLa secuencia %1, %2 no est definidaDesconocidodesconocido:Cancelar sus modificaciones?Q&uitar sombra,RLM Right-to-left markZEl fichero %1 ya existe. Desea reemplazarlo?.Colores &personalizados2fin de fichero inesperado QDB2Driver QMYSQLDriver QODBCDriverVEjecutivo (7,5 x 10 pulgadas, 191 x 254 mm)ZImposible inicializar el socket no bloqueante<PDF Pop directional formatting QDB2Driver QIBaseDriver QMYSQLDriver6La direccin est protegida6No se ha podido escribir %18se alcanz el lmite internoHCabecera de respuesta HTTP no vlidaError de expiracioD socks5 mientras se estableca una conexin al servidor socksCanal a&lfa:no se permiten referencias a entidades externas generales ya analizadas en el valor de un atributoMi&nimizarBImprimir primero la ltima pginaBorde izquierdoNCarta (8,5 x 11 pulgadas, 216 x 279 mm)FavoritosSiguienteAvanzar pgina,Una pgina hacia abajo QScrollBar,Una pgina hacia abajo2Una pgina a la izquierda QScrollBar2Una pgina a la izquierda Conexin cerradaQFtp Conexin cerrada4ZWNJ Zero width non-joiner2Ir al directorio superiorLInformacin del fichero previsualizadoMa&ximizarRestaurar abajo>Secuencia ambigua %1 no tratada2Operacin socket expiradaTipo< &Anterior Red inalcanzablefNo se ha indicado ningn servidor al que conectarseFRLO Start of right-to-left overridenerror en la declaracin de texto de una entidad externael ficherofin inesperadoZEl servidor cerr la conexin inesperadamenteXDemasiados ficheros abiertos simultneamenteJEl protocolo %1 no est contemplado*ZWJ Zero width joiner>La direccin no est disponible"B3 (353 x 500 mm).Crear una nueva carpeta Q3FileDialog.Crear una nueva carpeta:Enlace simblico a un fichero,LRM Left-to-right mark&Reproducir el medio Detener el medio,Insuficientes recursosSiguiente medioEl protocolo %1 no permite copiar o mover ficheros o directorios@Enlace simblico a un directorio,Solicitud interrumpidase ha producido un error durante el anlisis de la definicin de tipo de documentob<p>Este programa utiliza la versin %1 de Qt.</p>Borde derechojEl protocolo %1 no permite crear nuevos directoriosLanzar medio A7 (74 x 105 mm)Vista detallada Q3FileDialogVista detallada%1 Fichero no encontrado. Verifique que el nombre del fichero es correcto."A2 (420 x 594 mm)Orientacin: B7 (88 x 125 mm)BError: biblioteca Qt incompatible QMYSQLDriverQSQLite2Driver/z "(/8=CFKR\ahu{ $,9AHORenw '-39@ QProgressBarQDialog QDB2Driver QCheckBox QUndoStackQXml Q3TitleBar QMYSQLResultQDialogButtonBoxQ3Accel Q3TextEditQFtpQLibrary QFontDialogQMultiInputContextQRegExp QODBCResultQMultiInputContextPlugin QDB2Result QODBCDriver QDirModel QTcpServer QTDSDriver Q3FileDialog QSQLiteResultQSQLite2Result QToolButton QScrollBarQNativeSocketEngine Q3LocalFsQSlider QTextControl QPSQLDriver QColorDialog QIODevice QMYSQLDriver QAxSelect QWorkspace QApplication QOCIResult QShortcutQAbstractSpinBox QErrorMessage QSQLiteDriverQHostInfoAgent QUdpSocket QRadioButton QDateTimeEdit QMessageBox Q3TabDialogQSqlQTabBar QFileDialogQ3ProgressDialogQProgressDialogPPDOptionsModelQ3NetworkProtocolQMenu Q3MainWindowQWhatsThisAction QPrintDialogQUnicodeControlCharacterMenuQSQLite2DriverQObjectQPrintPropertiesDialog QComboBoxQ3Wizard Q3UrlOperator QInputContextQHttp QIBaseDriver Q3ToolBar QHostInfo QIBaseResultQWidget QLineEdit Q3DataTableQAbstractSocket QPSQLResultQSocks5SocketEngine QUndoModel QOCIDriver QUndoGroup QPushButtonQSpinBoxTreeLine-3.2.1/translations/qt_pt.qm000066400000000000000000002112641506556630100174500ustar00rootroot00000000000000+O+O8#H4HJĠK LD)L}PSlZrB[`;[`\kU__1?8E,p0v% O%G400:0y0|00X55 D= DKn+L,>,ֽFH5 4H5=H5KH5f pf1f;fIf|Hfflb<>L `Ҟ`_A2 ege>DeLWįįޓ y,*y*yo*y*TL*0'*0+Fy+F+f+fC+z0+d+p0+R+z0U+u+8+Ct+L+y+Z+į+įpc+įۈ+0F0iG8Hw9Hw99"I.4IJ+J6xJ61J69J6>nJ6yJ6{J6VJ6KGeLZPLL1Lb !O|1RPFEPFE{PFEuTQV1V1Vl VϞWWT?WT%X;XeX˙<]XY Zg8\]4\]4H\|^v7jv"fSIA)[;IHyYɵn2@ɵn^ɵneɵnqɵnɵnUɵn) W B.RMElPqH-`<p5#QL%UT*42CCCe#D"uD1QMaR?CfP loR+Xw^}a|{yW2{2*.?*l dyvjurgR "l)*-T/=Ni1$<5~P< k?N{Nky]`4`  G)i 676x6^TB3p=}F,EE(@j{.8AARb[yLns4ukMxMEOREX&ww!e)*/eN5^;ByoOZfH`xcփu(% h$$*.(ԍ^ n,a;yF&H`m/_IxS.YMOYMXuh^ i%ssc~wOۊ1NVz]]MIII5I9ZI[II&IIYɉiy Iȉ  Iˉʉ IIuDS*uDZcoJ,,p,,,cxɘeŤ5$fR afRINƛIc#PqUV:Vz ǙJ .h*$%C ?"sKN;MKR~]]]dky^f{yG%Mصǥѧ+t{yr %.eC-q5|ƨyƨ˾e]ҝz է?f~bI5~bKo !c++3/!/V6 kGNLAUٿPѧ9Ui}UZÖZZZ>^ne iSiZy;r{}uk}w}w}w!jtMt.4.PDt([tYt_ Fv ʢ5oʢd6bdvwdd59b)ؘUBw0mu b2?6TCU]DK1U|'arut}wZ}$}$Շ}$ZK<;- /YEMquTi~5kEXU HbDbGlgAi$ax1 `z*2dsU5^z@>mNnДb*C<ʴ5yPʴ5ԄD)dF5F5zgYI $IHmAsp 5 }$w qeWc ڤ Et E AcP AcJk 35q K!?E@ bb b` b` i3% la|p lf |U t tJ. m @t (  > o f u K %'_   )u */ 7u =M B2 T^‡ ] `^g ` c( dי e eH f1Q& gn k, rD": x ~dQ $Q 9 I'S I-) I7 ; v  Je %p* ,y ,B +! ˔L P' PX Q Yb 68 :/ f  f D 4a s sF AAUE :& m, #-tw 0N+ E9 L' L Mc\=! Sc Vh ]$3 f) f)D io>O m` A w~ H7 HC3 $E .@Ӫ  iB / p ܖ J JG/ t.4 kڙ Ӈ k ̺M< -DNU k k U)[ < 0F  R  Z α xH] ./F 7FD >U >V >W >]6 >j5 >o >b > DT I. RVJ RV RV S.@ S Y [y j7oB@ p/ . Bfh ; T2 TrQ T T i g 4 H Sp )d, C .3 ._c .sY . a yS | U t :b[u ʜ- +>0 0E ;ɾ Ptz Pt9 feE fe g iFC iH if u2 w w w> w}O w}: w} Pm X ^| }nS R6 X - D? t5z( t5 {L  )J T)gT**(%*/E)c/Em=BkI_[XRu[ a.:dvɅYy$~\SiB&cݖ[yrE  F^"#n$U%4=o%4K-v 0i)0͎1c92wT~D!5HWJd\ZL$.c5ic5iCyC" {~a` :FNAYkyPt2,q@A[ikSobre o %1About %1MAC_APPLICATION_MENUOcultar %1Hide %1MAC_APPLICATION_MENUOcultar Outros Hide OthersMAC_APPLICATION_MENUPreferncias &Preferences...MAC_APPLICATION_MENUEncerrar %1Quit %1MAC_APPLICATION_MENUServiosServicesMAC_APPLICATION_MENUMostrar TudoShow AllMAC_APPLICATION_MENU"%1, %2 indefinido%1, %2 not definedQ3Accel,%1 ambguo no tratadoAmbiguous %1 not handledQ3AccelRemoverDelete Q3DataTable FalsoFalse Q3DataTableInserirInsert Q3DataTableVerdadeiroTrue Q3DataTableActualizarUpdate Q3DataTablez%1 Ficheiro no encontrado. Verifique a localizao e o nome.+%1 File not found. Check path and filename. Q3FileDialog&Apagar&Delete Q3FileDialog&No&No Q3FileDialog&OK&OK Q3FileDialog &Abrir&Open Q3FileDialog&Mudar Nome&Rename Q3FileDialog&Gravar&Save Q3FileDialogNo &Ordenado &Unsorted Q3FileDialog&Sim&Yes Q3FileDialogJ<qt>Deseja mesmo apagar %1 "%2"?</qt>1Are you sure you wish to delete %1 "%2"? Q3FileDialog,Todos os Ficheiros (*) All Files (*) Q3FileDialog0Todos os Ficheiros (*.*)All Files (*.*) Q3FileDialogAtributos Attributes Q3FileDialog RecuarBack Q3FileDialogCancelarCancel Q3FileDialog6Copiar ou Mover um FicheiroCopy or Move a File Q3FileDialog Criar Nova PastaCreate New Folder Q3FileDialogDataDate Q3FileDialogApagar %1 Delete %1 Q3FileDialogVista Detalhada Detail View Q3FileDialog PastaDir Q3FileDialog Pastas Directories Q3FileDialog Pasta: Directory: Q3FileDialogErroError Q3FileDialogFicheiroFile Q3FileDialog$&Nome do Ficheiro: File &name: Q3FileDialog$&Tipo de Ficheiro: File &type: Q3FileDialogProcurar PastaFind Directory Q3FileDialogInacessvel Inaccessible Q3FileDialogVista Abreviada List View Q3FileDialogVer &em: Look &in: Q3FileDialogNomeName Q3FileDialogNova Pasta New Folder Q3FileDialogNova Pasta %1 New Folder %1 Q3FileDialogNova Pasta 1 New Folder 1 Q3FileDialogPasta MeOne directory up Q3FileDialog AbrirOpen Q3FileDialog Abrir Open  Q3FileDialog8Antever Contedo do FicheiroPreview File Contents Q3FileDialog<Antever Informao do FicheiroPreview File Info Q3FileDialog&RecarregarR&eload Q3FileDialogApenas Leitura Read-only Q3FileDialog"Leitura e escrita Read-write Q3FileDialogLer: %1Read: %1 Q3FileDialogGuardar ComoSave As Q3FileDialog(Seleccione uma PastaSelect a Directory Q3FileDialog:Mostrar ficheiros &escondidosShow &hidden files Q3FileDialogTamanhoSize Q3FileDialogOrdenarSort Q3FileDialog$Ordenar pela &Data Sort by &Date Q3FileDialog$Ordenar pelo &Nome Sort by &Name Q3FileDialog*Ordenar pelo &Tamanho Sort by &Size Q3FileDialogEspecialSpecial Q3FileDialog$Ligao para PastaSymlink to Directory Q3FileDialog*Ligao para FicheiroSymlink to File Q3FileDialog*Ligao para EspecialSymlink to Special Q3FileDialogTipoType Q3FileDialogApenas Escrita Write-only Q3FileDialogEscrever: %1 Write: %1 Q3FileDialoga pasta the directory Q3FileDialogo ficheirothe file Q3FileDialoga ligao the symlink Q3FileDialogBNo foi possvel criar a pasta %1Could not create directory %1 Q3LocalFs2No foi possvel abrir %1Could not open %1 Q3LocalFs>No foi possvel ler a pasta %1Could not read directory %1 Q3LocalFs`No foi possvel apagar o ficheiro ou a pasta %1%Could not remove file or directory %1 Q3LocalFsRNo foi possvel mudar o nome %1 para %2Could not rename %1 to %2 Q3LocalFs8Nao foi possvel escrever %1Could not write %1 Q3LocalFsConfigurar... Customize... Q3MainWindowAlinharLine up Q3MainWindowJOperao interrompida pelo utilizadorOperation stopped by the userQ3NetworkProtocolCancelarCancelQ3ProgressDialogAplicarApply Q3TabDialogCancelarCancel Q3TabDialogPredefiniesDefaults Q3TabDialog AjudaHelp Q3TabDialogOKOK Q3TabDialog&Copiar&Copy Q3TextEdit Co&lar&Paste Q3TextEdit&Refazer&Redo Q3TextEdit&Desfazer&Undo Q3TextEdit LimparClear Q3TextEditCor&tarCu&t Q3TextEdit Seleccionar Tudo Select All Q3TextEdit FecharClose Q3TitleBarFecha a janelaCloses the window Q3TitleBarNContm comandos para manipular a janela*Contains commands to manipulate the window Q3TitleBarvMostra o nome da janela e contm controlos para a manipularFDisplays the name of the window and contains controls to manipulate it Q3TitleBar@Coloca a janela em ecr completoMakes the window full screen Q3TitleBarMaximizarMaximize Q3TitleBarMinimizarMinimize Q3TitleBar.Tira a janela da frenteMoves the window out of the way Q3TitleBarZColoca uma janela maximizada no estado normal&Puts a maximized window back to normal Q3TitleBarZColoca uma janela minimizada no estado normalPuts a minimized back to normal Q3TitleBar Restaurar abaixo Restore down Q3TitleBarRestaurar acima Restore up Q3TitleBarSistemaSystem Q3TitleBarMais...More... Q3ToolBar(desconhecido) (unknown) Q3UrlOperatorO protocolo '%1' no suporta copiar ou mover ficheiros ou pastasIThe protocol `%1' does not support copying or moving files or directories Q3UrlOperatorhO protocolo '%1' no suporta criao de novas pastas;The protocol `%1' does not support creating new directories Q3UrlOperatordO protocolo '%1' no suporta obteno de ficheiros0The protocol `%1' does not support getting files Q3UrlOperator^O protocolo '%1' no suporta listagem de pastas6The protocol `%1' does not support listing directories Q3UrlOperatorfO protocolo '%1' no suporta colocao de ficheiros0The protocol `%1' does not support putting files Q3UrlOperator|O protocolo '%1' no suporta eliminao de ficheiros ou pastas@The protocol `%1' does not support removing files or directories Q3UrlOperatorO protocolo '%1' no suporta mudana de nome de ficheiros ou pastas@The protocol `%1' does not support renaming files or directories Q3UrlOperator@O protocolo '%1' no suportado"The protocol `%1' is not supported Q3UrlOperator&Cancelar&CancelQ3Wizard&Terminar&FinishQ3Wizard &Ajuda&HelpQ3Wizard&Avanar >&Next >Q3Wizard< &Recuar< &BackQ3Wizard Ligao recusadaConnection refusedQAbstractSocket Ligao expiradaConnection timed outQAbstractSocket(Mquina desconhecidaHost not foundQAbstractSocket"Rede inalcanvelNetwork unreachableQAbstractSocket$'Socket' desligadoSocket is not connectedQAbstractSocket:Operao de 'socket' expiradaSocket operation timed outQAbstractSocket&Passo acima&Step upQAbstractSpinBoxPasso &abaixo Step &downQAbstractSpinBoxActivarActivate QApplicationJActiva a janela principal do programa#Activates the program's main window QApplicationdO executvel '%1' requere Qt %2, Qt %3 encontrado.,Executable '%1' requires Qt %2, found Qt %3. QApplicationTErro de Incompatibilidade da Biblioteca QtIncompatible Qt Library Error QApplication&Cancelar&Cancel QAxSelect&Objecto COM: COM &Object: QAxSelectOKOK QAxSelect8Seleccionar Controlo ActiveXSelect ActiveX Control QAxSelectActivarCheck QCheckBoxComutarToggle QCheckBoxDesactivarUncheck QCheckBox@&Adicionar s Cores Customizadas&Add to Custom Colors QColorDialogCores &bsicas &Basic colors QColorDialog&Cores c&ustomizadas&Custom colors QColorDialogV&erde:&Green: QColorDialog&Vermelho:&Red: QColorDialog&Saturao:&Sat: QColorDialog&Valor:&Val: QColorDialog*Canal &transparncia:A&lpha channel: QColorDialog &Azul:Bl&ue: QColorDialog C&or:Hu&e: QColorDialog FecharClose QComboBox FalsoFalse QComboBox AbrirOpen QComboBoxVerdadeiroTrue QComboBoxLFinalizao de transaco no possvelUnable to commit transaction QDB2Driver(Ligao no possvelUnable to connect QDB2DriverFAnulao de transaco no possvelUnable to rollback transaction QDB2DriverFFinalizao automtica no possvelUnable to set autocommit QDB2Driver@Ligao de varivel no possvelUnable to bind variable QDB2Result*Execuo no possvelUnable to execute statement QDB2ResultBObteno do primeiro no possvelUnable to fetch first QDB2ResultBObteno do seguinte no possvelUnable to fetch next QDB2ResultFObteno do registo %1 no possvelUnable to fetch record %1 QDB2Result.Preparao no possvelUnable to prepare statement QDB2ResultAMAM QDateTimeEditPMPM QDateTimeEditamam QDateTimeEditpmpm QDateTimeEditO Que Isto? What's This?QDialog&Cancelar&CancelQDialogButtonBox&Fechar&CloseQDialogButtonBox&No&NoQDialogButtonBox&OK&OKQDialogButtonBox&Gravar&SaveQDialogButtonBox&Sim&YesQDialogButtonBoxAbortarAbortQDialogButtonBoxAplicarApplyQDialogButtonBoxCancelarCancelQDialogButtonBox FecharCloseQDialogButtonBox"Fechar sem GravarClose without SavingQDialogButtonBoxDescartarDiscardQDialogButtonBoxNo Gravar Don't SaveQDialogButtonBox AjudaHelpQDialogButtonBoxIgnorarIgnoreQDialogButtonBoxN&o para Todos N&o to AllQDialogButtonBoxOKOKQDialogButtonBox AbrirOpenQDialogButtonBoxRestaurarResetQDialogButtonBox.Restaurar PredefiniesRestore DefaultsQDialogButtonBox Tentar NovamenteRetryQDialogButtonBox GravarSaveQDialogButtonBoxGravar TodosSave AllQDialogButtonBoxSim para &Todos Yes to &AllQDialogButtonBox&Data de Modificao Date Modified QDirModelTipoKind QDirModelNomeName QDirModelTamanhoSize QDirModelTipoType QDirModel FecharClose QDockWidget MenosLessQDoubleSpinBoxMaisMoreQDoubleSpinBox&OK&OK QErrorMessage@&Mostrar esta mensagem novamente&Show this message again QErrorMessage&Mensagem Depurao:Debug Message: QErrorMessageErro Fatal: Fatal Error: QErrorMessage Aviso:Warning: QErrorMessagez%1 Pasta no encontrada. Por favor verifique o nome da pasta.K%1 Directory not found. Please verify the correct directory name was given. QFileDialog%1 Ficheiro no encontrado. Por favor verifique o nome do ficheiro.A%1 File not found. Please verify the correct file name was given. QFileDialog@%1 j existe. Deseja substituir?-%1 already exists. Do you want to replace it? QFileDialog&Apagar&Delete QFileDialog &Abrir&Open QFileDialog&Mudar o Nome&Rename QFileDialog&Gravar&Save QFileDialog'%1' est protegido contra escrita. Deseja apagar de qualquer forma?9'%1' is write protected. Do you want to delete it anyway? QFileDialog,Todos os Ficheiros (*) All Files (*) QFileDialog0Todos os Ficheiros (*.*)All Files (*.*) QFileDialog2Deseja mesmo apagar '%1'?!Are sure you want to delete '%1'? QFileDialog RecuarBack QFileDialog@No foi possvel apagar a pasta.Could not delete directory. QFileDialog Criar Nova PastaCreate New Folder QFileDialogVista Detalhada Detail View QFileDialog Pastas Directories QFileDialog Pasta: Directory: QFileDialogUnidadeDrive QFileDialogFicheiroFile QFileDialog$&Nome do Ficheiro: File &name: QFileDialog$FIcheiros do tipo:Files of type: QFileDialogProcurar PastaFind Directory QFileDialogSeguinteForward QFileDialogVista Abreviada List View QFileDialog O Meu Computador My Computer QFileDialogNova Pasta New Folder QFileDialog AbrirOpen QFileDialogPasta MeParent Directory QFileDialogGravar ComoSave As QFileDialog:Mostrar ficheiros &escondidosShow &hidden files QFileDialogDesconhecidoUnknown QFileDialog&Data de Modificao Date ModifiedQFileSystemModelTipoKindQFileSystemModel O Meu Computador My ComputerQFileSystemModelNomeNameQFileSystemModelTamanhoSizeQFileSystemModelTipoTypeQFileSystemModel&Tipo de Letra&Font QFontDialog&Tamanho&Size QFontDialog&Sublinhar &Underline QFontDialogEfeitosEffects QFontDialog*&Estilo Tipo de Letra Font st&yle QFontDialogAmostraSample QFontDialog0Seleccione Tipo de Letra Select Font QFontDialog&Riscar Stri&keout QFontDialog&&Sistema de EscritaWr&iting System QFontDialog:A mudana de pasta falhou: %1Changing directory failed: %1QFtp$Ligado ao servidorConnected to hostQFtp*Ligado ao servidor %1Connected to host %1QFtp@A ligao ao servidor falhou: %1Connecting to host failed: %1QFtpLigao fechadaConnection closedQFtp2Ligao de dados recusada&Connection refused for data connectionQFtp>Ligao ao servidor %1 recusadaConnection refused to host %1QFtp(Ligao a %1 fechadaConnection to %1 closedQFtp:A criao da pasta falhou: %1Creating directory failed: %1QFtpBA descarga do ficheiro falhou: %1Downloading file failed: %1QFtp,Servidor %1 encontrado Host %1 foundQFtp4Servidor %1 no encontradoHost %1 not foundQFtp&Servidor encontrado Host foundQFtp<A listagem da pasta falhou: %1Listing directory failed: %1QFtp2A autenticao falhou: %1Login failed: %1QFtpDesligado Not connectedQFtp:A remoo da pasta falhou: %1Removing directory failed: %1QFtp@A remoo do ficheiro falhou: %1Removing file failed: %1QFtp"Erro desconhecido Unknown errorQFtpJO carregamento do ficheiro falhou: %1Uploading file failed: %1QFtpLTRQT_LAYOUT_DIRECTIONQGuiApplication"Erro desconhecido Unknown error QHostInfo.Servidor No encontradoHost not foundQHostInfoAgent:Tipo de endereo desconhecidoUnknown address typeQHostInfoAgent"Erro desconhecido Unknown errorQHostInfoAgent$Ligado ao servidorConnected to hostQHttp*Ligado ao servidor %1Connected to host %1QHttpLigao fechadaConnection closedQHttp Ligao recusadaConnection refusedQHttp(Ligao a %1 fechadaConnection to %1 closedQHttp(O pedido HTTP falhouHTTP request failedQHttp,Servidor %1 encontrado Host %1 foundQHttp4Servidor %1 no encontradoHost %1 not foundQHttp&Servidor encontrado Host foundQHttp6Corpo parcial HTTP invlidoInvalid HTTP chunked bodyQHttpFCabealho de resposta HTTP invlidoInvalid HTTP response headerQHttp4Nenhum servidor para ligarNo server set to connect toQHttpPedido abortadoRequest abortedQHttpVO servidor fechou a ligao inesperadamente%Server closed connection unexpectedlyQHttp"Erro desconhecido Unknown errorQHttp4Tamanho de contedo erradoWrong content lengthQHttpJNo foi possvel iniciar a transacoCould not start transaction QIBaseDriver:Erro ao abrir a base de dadosError opening database QIBaseDriverNNo foi possvel finalizar a transacoUnable to commit transaction QIBaseDriverHNo foi possvel anular a transacoUnable to rollback transaction QIBaseDriverFNo foi possvel alocar a expressoCould not allocate statement QIBaseResultbNo foi possvel descrever a expresso de entrada"Could not describe input statement QIBaseResultLNo foi possvel descrever a expressoCould not describe statement QIBaseResultTNo foi possvel obter o elemento seguinteCould not fetch next item QIBaseResultDNo foi possvel encontrar o arrayCould not find array QIBaseResultPNo foi possvel obter os dados do arrayCould not get array data QIBaseResultTNo foi possvel obter informao da queryCould not get query info QIBaseResult\No foi possvel obter informao da expressoCould not get statement info QIBaseResultJNo foi possvel preparar a expressoCould not prepare statement QIBaseResultJNo foi possvel iniciar a transacoCould not start transaction QIBaseResultFNo foi possvel fechar a expressoUnable to close statement QIBaseResultNNo foi possvel finalizar a transacoUnable to commit transaction QIBaseResult:No foi possvel criar o BLOBUnable to create BLOB QIBaseResultBNo foi possvel executar a queryUnable to execute query QIBaseResult:No foi possvel abrir o BLOBUnable to open BLOB QIBaseResult6No foi possvel ler o BLOBUnable to read BLOB QIBaseResult@No foi possvel escrever o BLOBUnable to write BLOB QIBaseResult8Dispositivo sem espao livreNo space left on device QIODevice:Ficheiro ou pasta inexistenteNo such file or directory QIODevice Permisso negadaPermission denied QIODevice8Demasiados ficheiros abertosToo many open files QIODevice"Erro desconhecido Unknown error QIODevice4Mtodo de entrada Max OS XMac OS X input method QInputContext2Mtodo de entrada WindowsWindows input method QInputContextXIMXIM QInputContext*Mtodo de entrada XIMXIM input method QInputContext@No foi possivel mapear '%1': %2Could not mmap '%1': %2QLibraryFNo foi possvel desmapear '%1': %2Could not unmap '%1': %2QLibrarydDados de verificao do plugin incorrectos em '%1')Plugin verification data mismatch in '%1'QLibraryO plugin '%1' usa uma biblioteca Qt incompatvel. (%2.%3.%4) [%5]=The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]QLibraryO plugin '%1' usa uma biblioteca Qt incompatvel. A chave de compilao esperada "%2", ficou "%3"OThe plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3"QLibrary"Erro desconhecido Unknown errorQLibrary&Copiar&Copy QLineEdit Co&lar&Paste QLineEdit&Refazer&Redo QLineEdit&Desfazer&Undo QLineEditCor&tarCu&t QLineEdit ApagarDelete QLineEdit Seleccionar Tudo Select All QLineEditJNo foi possvel iniciar a transacoUnable to begin transaction QMYSQLDriverNNo foi possvel finalizar a transacoUnable to commit transaction QMYSQLDriverLNo foi possvel estabelecer a ligaoUnable to connect QMYSQLDriverPNo foi possvel abrir a base de dados 'Unable to open database ' QMYSQLDriverHNo foi possvel anular a transacoUnable to rollback transaction QMYSQLDriverjNo foi possvel fazer a ligao dos valores externosUnable to bind outvalues QMYSQLResultRNo foi possvel fazer a ligao do valorUnable to bind value QMYSQLResultBNo foi possvel executar a queryUnable to execute query QMYSQLResultJNo foi possvel executar a expressoUnable to execute statement QMYSQLResult8No foi possvel obter dadosUnable to fetch data QMYSQLResultJNo foi possvel preparar a expressoUnable to prepare statement QMYSQLResultLNo foi possvel restaurar a expressoUnable to reset statement QMYSQLResultHNo foi possvel guardar o resultadoUnable to store result QMYSQLResultfNo foi possvel guardar os resultados da expresso!Unable to store statement results QMYSQLResult%1 - [%2] %1 - [%2] QMdiSubWindow&Fechar&Close QMdiSubWindow &Mover&Move QMdiSubWindow&Restaurar&Restore QMdiSubWindow&Tamanho&Size QMdiSubWindow FecharClose QMdiSubWindow AjudaHelp QMdiSubWindowMa&ximizar Ma&ximize QMdiSubWindowMaximizarMaximize QMdiSubWindowMenuMenu QMdiSubWindowMi&nimizar Mi&nimize QMdiSubWindowMinimizarMinimize QMdiSubWindowRestaurar Baixo Restore Down QMdiSubWindow&Permanecer no &Topo Stay on &Top QMdiSubWindow FecharCloseQMenuExecutarExecuteQMenu AbrirOpenQMenuAcerca do QtAbout Qt QMessageBox AjudaHelp QMessageBox.No Mostrar Detalhes...Hide Details... QMessageBoxOKOK QMessageBox&Mostrar Detalhes...Show Details... QMessageBox8Seleccione Mtodo de Entrada Select IMQMultiInputContextDSeleccionador de mtodo de entradaMultiple input method switcherQMultiInputContextPluginSeleccionador de mtodo de entrada que utiliza o menu de contexto dos elementos de textoMMultiple input method switcher that uses the context menu of the text widgetsQMultiInputContextPlugin\Outro 'socket' j est escuta no mesmo porto4Another socket is already listening on the same portQNativeSocketEngineTentativa de utilizao de 'socket' IPv6 numa plataforma sem suporte IPv6=Attempt to use IPv6 socket on a platform with no IPv6 supportQNativeSocketEngine Ligao recusadaConnection refusedQNativeSocketEngine Ligao expiradaConnection timed outQNativeSocketEngineLDatagrama demasiado grande para enviarDatagram was too large to sendQNativeSocketEngine(Mquina inalcanvelHost unreachableQNativeSocketEngine<Descritor de 'socket' invlidoInvalid socket descriptorQNativeSocketEngineErro de rede Network errorQNativeSocketEngine2Operao de rede expiradaNetwork operation timed outQNativeSocketEngine"Rede inalcanvelNetwork unreachableQNativeSocketEngine0Operao em no 'socket'Operation on non-socketQNativeSocketEngineSem recursosOut of resourcesQNativeSocketEngine Permisso negadaPermission deniedQNativeSocketEngine>Tipo de protocolo no suportadoProtocol type not supportedQNativeSocketEngine<O endereo no est disponvelThe address is not availableQNativeSocketEngine2O endereo est protegidoThe address is protectedQNativeSocketEngineHO endereo de ligao j est em uso#The bound address is already in useQNativeSocketEngineBA mquina remota fechou a ligao%The remote host closed the connectionQNativeSocketEnginehNo foi possvel inicializar 'socket' de transmisso%Unable to initialize broadcast socketQNativeSocketEnginehNo foi possvel inicializar 'socket' no bloqueante(Unable to initialize non-blocking socketQNativeSocketEngineJNo foi possvel receber uma mensagemUnable to receive a messageQNativeSocketEngineHNo foi possvel enviar uma mensagemUnable to send a messageQNativeSocketEngine2No foi possvel escreverUnable to writeQNativeSocketEngine"Erro desconhecido Unknown errorQNativeSocketEngineDOperao de 'socket' no suportadaUnsupported socket operationQNativeSocketEngineJNo foi possvel iniciar a transacoUnable to begin transaction QOCIDriver8No foi possvel inicializarUnable to initialize QOCIDriver6No foi possvel autenticarUnable to logon QOCIDriverFNo foi possvel alocar a expressoUnable to alloc statement QOCIResultNo foi possvel fazer a licao da coluna para execuo 'batch''Unable to bind column for batch execute QOCIResultVNo foi possvel fazer o ligamento do valorUnable to bind value QOCIResult`No foi possvel executar a expresso de 'batch'!Unable to execute batch statement QOCIResultJNo foi possvel executar a expressoUnable to execute statement QOCIResultFNo foi possvel passar ao seguinteUnable to goto next QOCIResultJNo foi possvel preparar a expressoUnable to prepare statement QOCIResultNNo foi possvel finalizar a transacoUnable to commit transaction QODBCDriver,No foi possvel ligarUnable to connect QODBCDriverNo foi possvel ligar - O 'driver' no suporta todas as funcionalidades necessriasCUnable to connect - Driver doesn't support all needed functionality QODBCDriverfNo foi possvel desactivar finalizao automticaUnable to disable autocommit QODBCDriver^No foi possvel activar finalizao automticaUnable to enable autocommit QODBCDriverHNo foi possvel anular a transacoUnable to rollback transaction QODBCDriver(QODBCResult::reset: No foi possvel definir 'SQL_CURSOR_STATIC' como atributo da expresso. Por favor verifique a configurao do seu 'driver' ODBCyQODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration QODBCResult\No foi possvel fazer o ligamento da varivelUnable to bind variable QODBCResultJNo foi possvel executar a expressoUnable to execute statement QODBCResultBObteno do primeiro no possvelUnable to fetch first QODBCResultBNo foi possvel obter o seguinteUnable to fetch next QODBCResultJNo foi possvel preparar a expressoUnable to prepare statement QODBCResult IncioHomeQObjectNomeNameQPPDOptionsModel ValorValueQPPDOptionsModelJNo foi possvel iniciar a transacoCould not begin transaction QPSQLDriverNNo foi possvel finalizar a transacoCould not commit transaction QPSQLDriverHNo foi possvel anular a transacoCould not rollback transaction QPSQLDriver,No foi possvel ligarUnable to connect QPSQLDriver@No foi possvel criar a 'query'Unable to create query QPSQLResultPaisagem LandscapeQPageSetupWidgetTamanho pgina: Page size:QPageSetupWidgetFonte papel: Paper source:QPageSetupWidgetRetratoPortraitQPageSetupWidget"Erro desconhecido Unknown error QPluginLoader@%1 j existe. Deseja substituir?/%1 already exists. Do you want to overwrite it? QPrintDialog@<qt>Deseja gravar por cima?</qt>%Do you want to overwrite it? QPrintDialog$A0 (841 x 1189 mm)A0 (841 x 1189 mm) QPrintDialog"A1 (594 x 841 mm)A1 (594 x 841 mm) QPrintDialog"A2 (420 x 594 mm)A2 (420 x 594 mm) QPrintDialog"A3 (297 x 420 mm)A3 (297 x 420 mm) QPrintDialogPA4 (210 x 297 mm, 8.26 x 11.7 polegadas)%A4 (210 x 297 mm, 8.26 x 11.7 inches) QPrintDialog"A5 (148 x 210 mm)A5 (148 x 210 mm) QPrintDialog"A6 (105 x 148 mm)A6 (105 x 148 mm) QPrintDialog A7 (74 x 105 mm)A7 (74 x 105 mm) QPrintDialogA8 (52 x 74 mm)A8 (52 x 74 mm) QPrintDialogA9 (37 x 52 mm)A9 (37 x 52 mm) QPrintDialog,Nomes Alternativos: %1 Aliases: %1 QPrintDialog&B0 (1000 x 1414 mm)B0 (1000 x 1414 mm) QPrintDialog$B1 (707 x 1000 mm)B1 (707 x 1000 mm) QPrintDialog B10 (31 x 44 mm)B10 (31 x 44 mm) QPrintDialog"B2 (500 x 707 mm)B2 (500 x 707 mm) QPrintDialog"B3 (353 x 500 mm)B3 (353 x 500 mm) QPrintDialog"B4 (250 x 353 mm)B4 (250 x 353 mm) QPrintDialogPB5 (176 x 250 mm, 6.93 x 9.84 polegadas)%B5 (176 x 250 mm, 6.93 x 9.84 inches) QPrintDialog"B6 (125 x 176 mm)B6 (125 x 176 mm) QPrintDialog B7 (88 x 125 mm)B7 (88 x 125 mm) QPrintDialogB8 (62 x 88 mm)B8 (62 x 88 mm) QPrintDialogB9 (44 x 62 mm)B9 (44 x 62 mm) QPrintDialog$C5E (163 x 229 mm)C5E (163 x 229 mm) QPrintDialog$DLE (110 x 220 mm)DLE (110 x 220 mm) QPrintDialogXExecutivo (7.5 x 10 polegadas, 191 x 254 mm))Executive (7.5 x 10 inches, 191 x 254 mm) QPrintDialogNo possvel escrever no ficheiro %1. Por favor escolha um nome diferente.=File %1 is not writable. Please choose a different file name. QPrintDialog"O ficheiro existe File exists QPrintDialog(Folio (210 x 330 mm)Folio (210 x 330 mm) QPrintDialog*Ledger (432 x 279 mm)Ledger (432 x 279 mm) QPrintDialogPLegal (8.5 x 14 polegadas, 216 x 356 mm)%Legal (8.5 x 14 inches, 216 x 356 mm) QPrintDialogPCarta (8.5 x 11 polegadas, 216 x 279 mm)&Letter (8.5 x 11 inches, 216 x 279 mm) QPrintDialogOKOK QPrintDialogImprimirPrint QPrintDialog4Imprimir Para Ficheiro ...Print To File ... QPrintDialogImprimir todas Print all QPrintDialog&Seleco de pginas Print range QPrintDialog*Seleco de ImpressoPrint selection QPrintDialog.Tablide (279 x 432 mm)Tabloid (279 x 432 mm) QPrintDialogJEnvelope #10 Comum EUA (105 x 241 mm)%US Common #10 Envelope (105 x 241 mm) QPrintDialog"ligado localmentelocally connected QPrintDialogdesconhecidounknown QPrintDialog FecharCloseQPrintPreviewDialogPaisagem LandscapeQPrintPreviewDialogRetratoPortraitQPrintPreviewDialog JuntarCollateQPrintSettingsOutput CpiasCopiesQPrintSettingsOutput OpesOptionsQPrintSettingsOutputPginas de Pages fromQPrintSettingsOutputImprimir todas Print allQPrintSettingsOutput&Seleco de pginas Print rangeQPrintSettingsOutputSeleco SelectionQPrintSettingsOutputatoQPrintSettingsOutputImpressoraPrinter QPrintWidgetCancelarCancelQProgressDialog AbrirOpen QPushButtonActivarCheck QRadioButtonDm sintaxe de classe de caracteresbad char class syntaxQRegExp2m sintaxe de antecipaobad lookahead syntaxQRegExp.m sintaxe de repetiobad repetition syntaxQRegExp^funcionalidade desactivada est a ser utilizadadisabled feature usedQRegExp(valor octal invlidoinvalid octal valueQRegExp0limite interno alcanadomet internal limitQRegExp:delimitador esquerdo em faltamissing left delimQRegExpsem errosno error occurredQRegExpfim inesperadounexpected endQRegExp6Erro ao abrir base de dadosError to open databaseQSQLite2DriverJNo foi possvel iniciar a transacoUnable to begin transactionQSQLite2DriverNNo foi possvel finalizar a transacoUnable to commit transactionQSQLite2DriverHNo foi possvel anular a transacoUnable to rollback TransactionQSQLite2DriverJNo foi possvel executar a expressoUnable to execute statementQSQLite2ResultHNo foi possvel obter os resultadosUnable to fetch resultsQSQLite2Result<Erro ao fechar a base de dadosError closing database QSQLiteDriver:Erro ao abrir a base de dadosError opening database QSQLiteDriverJNo foi possvel iniciar a transacoUnable to begin transaction QSQLiteDriverNNo foi possvel finalizar a transacoUnable to commit transaction QSQLiteDriverVIncorrespondncia de contagem de parmetrosParameter count mismatch QSQLiteResult^No foi possvel fazer a ligao dos parametrosUnable to bind parameters QSQLiteResultJNo foi possvel executar a expressoUnable to execute statement QSQLiteResult<No foi possvel obter a linhaUnable to fetch row QSQLiteResultLNo foi possvel restaurar a expressoUnable to reset statement QSQLiteResult FundoBottom QScrollBarBorda esquerda Left edge QScrollBarLinha abaixo Line down QScrollBarLinha acimaLine up QScrollBar"Pgina para baixo Page down QScrollBar(Pgina para esquerda Page left QScrollBar&Pgina para direita Page right QScrollBar Pgina para cimaPage up QScrollBarPosioPosition QScrollBarBorda direita Right edge QScrollBar&Deslizar para baixo Scroll down QScrollBarDeslizar aqui Scroll here QScrollBar,Deslizar para esquerda Scroll left QScrollBar.Deslizar para a direita Scroll right QScrollBar$Deslizar para cima Scroll up QScrollBarTopoTop QScrollBar++ QShortcutAltAlt QShortcutAnteriorBack QShortcutBackspace Backspace QShortcutBacktabBacktab QShortcutBass Boost Bass Boost QShortcutBass Baixo Bass Down QShortcutBass CimaBass Up QShortcut ChamarCall QShortcutCaps Lock Caps Lock QShortcutCapsLockCapsLock QShortcutContexto1Context1 QShortcutContexto2Context2 QShortcutContexto3Context3 QShortcutContexto4Context4 QShortcutCtrlCtrl QShortcut DeleteDel QShortcut DeleteDelete QShortcut BaixoDown QShortcutEndEnd QShortcut EnterEnter QShortcutEscEsc QShortcut EscapeEscape QShortcutF%1F%1 QShortcutFavoritos Favorites QShortcutInverterFlip QShortcutSeguinteForward QShortcutDesligarHangup QShortcut AjudaHelp QShortcutHomeHome QShortcut Pgina Principal Home Page QShortcut InsertIns QShortcut InsertInsert QShortcutExecutar (0) Launch (0) QShortcutExecutar (1) Launch (1) QShortcutExecutar (2) Launch (2) QShortcutExecutar (3) Launch (3) QShortcutExecutar (4) Launch (4) QShortcutExecutar (5) Launch (5) QShortcutExecutar (6) Launch (6) QShortcutExecutar (7) Launch (7) QShortcutExecutar (8) Launch (8) QShortcutExecutar (9) Launch (9) QShortcutExecutar (A) Launch (A) QShortcutExecutar (B) Launch (B) QShortcutExecutar (C) Launch (C) QShortcutExecutar (D) Launch (D) QShortcutExecutar (E) Launch (E) QShortcutExecutar (F) Launch (F) QShortcut&Correio Electrnico Launch Mail QShortcut Mdia Launch Media QShortcutEsquerdaLeft QShortcutMdia Seguinte Media Next QShortcutTocar Mdia Media Play QShortcutMdia AnteriorMedia Previous QShortcutGravao Mdia Media Record QShortcutParar Mdia Media Stop QShortcutMenuMenu QShortcutMetaMeta QShortcutNoNo QShortcutNum LockNum Lock QShortcutNum LockNumLock QShortcutNumber Lock Number Lock QShortcutAbrir EndereoOpen URL QShortcutPage Down Page Down QShortcutPage UpPage Up QShortcut PausePause QShortcut PgDownPgDown QShortcutPgUpPgUp QShortcut PrintPrint QShortcutPrint Screen Print Screen QShortcutRefrescarRefresh QShortcut ReturnReturn QShortcutDireitaRight QShortcutScroll Lock Scroll Lock QShortcutScrollLock ScrollLock QShortcutProcurarSearch QShortcut SelectSelect QShortcut ShiftShift QShortcut SpaceSpace QShortcutHibernaoStandby QShortcut PararStop QShortcut SysReqSysReq QShortcutSystem RequestSystem Request QShortcutTabTab QShortcutTreble Baixo Treble Down QShortcutTreble Cima Treble Up QShortcutCimaUp QShortcutVolume Cima Volume Down QShortcutVolume Mute Volume Mute QShortcutVolume Baixo Volume Up QShortcutSimYes QShortcut"Pgina para baixo Page downQSlider(Pgina para esquerda Page leftQSlider&Pgina para direita Page rightQSlider Pgina para cimaPage upQSliderPosioPositionQSlider2Operao de rede expiradaNetwork operation timed outQSocks5SocketEngine MenosLessQSpinBoxMaisMoreQSpinBoxCancelarCancelQSql.Cancelar as alteraes?Cancel your edits?QSqlConfirmarConfirmQSql ApagarDeleteQSql(Apagar este registo?Delete this record?QSqlInserirInsertQSqlNoNoQSql*Gravar as alteraes? Save edits?QSqlActualizarUpdateQSqlSimYesQSqlLNo foi possvel estabelecer a ligaoUnable to open connection QTDSDriverRNo foi possvel utilizar a base de dadosUnable to use database QTDSDriver,Deslizar para Esquerda Scroll LeftQTabBar*Deslizar para Direita Scroll RightQTabBar&Copiar&Copy QTextControl Co&lar&Paste QTextControl&Refazer&Redo QTextControl&Desfazer&Undo QTextControl<Copiar &Localizao da LigaoCopy &Link Location QTextControlCor&tarCu&t QTextControl ApagarDelete QTextControl Seleccionar Tudo Select All QTextControl AbrirOpen QToolButtonPressionarPress QToolButton@Esta plataforma no suporta IPv6#This platform does not support IPv6 QUdpSocketRefazerRedo QUndoGroupDesfazerUndo QUndoGroup<vazio> QUndoModelRefazerRedo QUndoStackDesfazerUndo QUndoStackHInserir carcter de controlo Unicode Insert Unicode control characterQUnicodeControlCharacterMenuVLRE Incio de encaixe esquerda-para-direita$LRE Start of left-to-right embeddingQUnicodeControlCharacterMenu>LRM Marca esquerda-para-direitaLRM Left-to-right markQUnicodeControlCharacterMenu`LRO Incio de sobreposio esquerda-para-direita#LRO Start of left-to-right overrideQUnicodeControlCharacterMenu<PDF Formatao pop direccionalPDF Pop directional formattingQUnicodeControlCharacterMenuVRLE Incio de encaixe direita-para-esquerda$RLE Start of right-to-left embeddingQUnicodeControlCharacterMenu>RLM Marca direita-para-esquerdaRLM Right-to-left markQUnicodeControlCharacterMenu`RLO Incio de sobreposio direita-para-esquerda#RLO Start of right-to-left overrideQUnicodeControlCharacterMenu>ZWJ Ligador de comprimento zeroZWJ Zero width joinerQUnicodeControlCharacterMenuHZWNJ No-ligador de comprimento zeroZWNJ Zero width non-joinerQUnicodeControlCharacterMenu>ZWSP Espao de comprimento zeroZWSP Zero width spaceQUnicodeControlCharacterMenu FundoBottomQWebPageIgnorarIgnoreQWebPageIgnorar Ignore Grammar context menu itemIgnoreQWebPageBorda esquerda Left edgeQWebPage"Pgina para baixo Page downQWebPage(Pgina para esquerda Page leftQWebPage&Pgina para direita Page rightQWebPage Pgina para cimaPage upQWebPageRestaurarResetQWebPageBorda direita Right edgeQWebPage&Deslizar para baixo Scroll downQWebPageDeslizar aqui Scroll hereQWebPage,Deslizar para esquerda Scroll leftQWebPage.Deslizar para a direita Scroll rightQWebPage$Deslizar para cima Scroll upQWebPage PararStopQWebPageTopoTopQWebPageDesconhecidoUnknownQWebPageO Que Isto? What's This?QWhatsThisAction**QWidget&Terminar&FinishQWizard &Ajuda&HelpQWizard&Avanar >&Next >QWizard< &Recuar< &BackQWizardCancelarCancelQWizard AjudaHelpQWizard%1 - [%2] %1 - [%2] QWorkspace&Fechar&Close QWorkspace &Mover&Move QWorkspace&Restaurar&Restore QWorkspace&Tamanho&Size QWorkspace&Sair Sombra&Unshade QWorkspace FecharClose QWorkspaceMa&ximizar Ma&ximize QWorkspaceMi&nimizar Mi&nimize QWorkspaceMinimizarMinimize QWorkspaceRestaurar Baixo Restore Down QWorkspaceSombr&aSh&ade QWorkspace&Permanecer no &Topo Stay on &Top QWorkspacedeclarao de codificao ou declarao nica esperada ao ler a declarao XMLYencoding declaration or standalone declaration expected while reading the XML declarationQXmlTerro na declarao de uma entidade externa3error in the text declaration of an external entityQXml6erro ao analisar comentrio$error occurred while parsing commentQXml6erro ao analisar o contedo$error occurred while parsing contentQXmlberro ao analisar a definio de tipo de documento5error occurred while parsing document type definitionQXml2erro ao analisar elemento$error occurred while parsing elementQXml6erro ao analisar referncia&error occurred while parsing referenceQXml<erro disparado pelo consumidorerror triggered by consumerQXmlreferncia de entidade geral analisada externa no permitida na DTD;external parsed general entity reference not allowed in DTDQXmlreferncia de entidade geral analisada externa no permitida no valor do atributoGexternal parsed general entity reference not allowed in attribute valueQXmlrreferncia de entidade geral interna no permitida na DTD4internal general entity reference not allowed in DTDQXmlVnome invlido de instruo de processamento'invalid name for processing instructionQXml(uma letra esperadaletter is expectedQXmlTmais de uma definio de tipo de documento&more than one document type definitionQXml.no ocorreu nenhum errono error occurredQXml(entidades recursivasrecursive entitiesQXmlbdeclarao nica esperada ao ler a declarao XMLAstandalone declaration expected while reading the XML declarationQXml2m combinao de etiqueta tag mismatchQXml&carcter inesperadounexpected characterQXml4fim de ficheiro inesperadounexpected end of fileQXmlnreferncia de entidade no analisada em contexto errado*unparsed entity reference in wrong contextQXmlNverso esperada ao ler a declarao XML2version expected while reading the XML declarationQXmlDvalor errado para declarao nica&wrong value for standalone declarationQXmlTreeLine-3.2.1/translations/qt_ru.qm000066400000000000000000004552511506556630100174610ustar00rootroot0000000000000055 W> D'2 DP+--|!RT,M~.!KxExy{+=rAa7L'jVB#F0|nsm2M6ec^q:Te |z!e&#\(9)*(L*(]*(*(*(*(Y*(*(*(*(U*(*(*/eK*ASf+ %+,N*;)=-?4@N9FoDKibO\c `cփd|f$~jCN mtէp/TB qtuu(Z}ka^.X,[Q_~, 0_[ G$2$9t$;SugS0(r^֊U nQ,sAю <3. n=&Hr+ ./rS=BZ?5)@`gCrIxSL6R>)YM]Yu,_oMubUC+c{Cc{DNc{E~dn_eskD>+n v'4O^IpBxQgۊEN]v)II3I-I G(FIYSiy KIc[!uDa}uDid?ݾ D uL o',,EC,v,P,]]l46f! ~2 ɘefRJ#*Gn9N-JTTP TQ >TR TS TT TU 1TV aTW TX TY \SW PqdVfR?BC+ UhQyp=?e l7$&~U)2@.yX58 8>1?"QF(KN L;MJN2'O{@V|Wj]4,]p|]ve4 e6; Cg^|knMrHwy}~1Z 5tFK>'WG%\dصٵ+ `Yzg;Y>JMczxAZ9\YqsYY% rn C-9 5C^i˾wRiZ>'i}%z9zߺt6䏥 f7tӒ롥EF3g!-d/ $~bI~bPM*Q!uT%?)ɯ+y+&Q+3o,$`/+0jIKh4~ҡ6 8- v<h<nTA'D^G]hGbOL|LAU{LOrPѧeUR iRCSfgLSnYU{*U;UToqV(c!YĻZ4l[ ]k*I^o2F^~͝^n_P_p&`74fgkQ)Mn$4̣oN"p4(pq"{ {*B}u}ww}!&>:r{  B\ v.OtNt#^38(P5<>|w bWWDfYtAtht _ @a25uFʢ$ʢIƴd%nd'dޣdGd59tz2э/)j[+kNSWD`}㵾;1rB>ktȗayU0R^dBhpAw$KBD,% t0bˌ25p6b:3>*K?;CUDJ0 LXLU|]\"aroldn8\sFY_Vu[7|#}wZ}$w^?Gϗ.Z.ZDjʆ$ZG[` ezdZk< K<3| +·z·6a׳*8QKТ~HCfC}r؞ etE\#b9%5PQw>-bD`F#%"'̌+i+)[.%4>P5kE7= =>1. ??@JCtISEfZF)NP~V%eV%gXU GC^MT^M_R`|bDbGb^hIUGi$ܢm5x1 z*2~OdUz6c.j4N3Fbm]l%BE/CbsiRaCUʴ5ʶ+ϡ$^ mԄ[۔#$Dd6AՆF5YDple1&DsIG=W $ }$ qeg[ ڤ ڥ)k d( E E AcL t "knv. 35ƴ R b, bb b`y gU hiF la la7 lfG qz s-3 tNי xq | J- tKr  .! y`  9D r x n . $|1 Űe Y+ ˰!   Y : 팤` 팤Ծ E %'{  L| Cy qX  D1z 5 } 9M o7K  1 !E '( '(b )f ) */ *ŎH .> 2* 7u ; =\ H  J" Q Rۮh Ty ` T^ Uj4 YHY \t ] ^& `p `l `o b c('! cE dht, eI e{ f1_ f*(/ g5U" gyX gn t xp ~vb $& [ Id m4 O  t f? j =)U| JN 3T $ ${ %p ,?W >r[ E! `j  4 B' T  v +  l2 ˔[ P L W,E 685 X I : F A f A~ u 4s .Zh "ú sE AAck 9  9 !i r %j #-t ' +i6 0N u =@! @ Aϥ CU[ F)3 LNc L Mc\ Su Vz> Zj ]qt0 ]$" c3 f= io>4 l# sk: spk wq= yCB ] H@  $D. .@}     zd; 5~ ~J b JE ? t. k=  : N>q /a ̷ ̺[ -D\ .; %o G ۷# 6 ky^  )yY }o  9 0N $r  5  I < ITk V %Z L  (G  c e  $ ! 5A "N%Ǒ .M 5! 7Fm :9J >c >f >g >{ >} > > >Ǎ > >3 > @ӊ A Ef K K) K Mbg Ođ RVL RVg SGͶ S+, WoŦ Y [ ^UT' hۮS j7o> p >r  Bx? _S & T! T Tߗ T) ys $ V T T t c S )dŏ T  ." .q . .~ . .n .qW   a eu( sh e %n ҂ K > Y  |} t8 aҦ  9 8< ? $a z ${v #=/ (I$ +> 0EZ 4~; 64~4 8 :n! ;ɾ Fg: K9 Pt| S, fev iFC~ iH iD jӮ} m9He n% u u * u$ v& ww w}w\ |[, u ^ hu <76 Jm ^ KI Y Rh %7% ˤ " U & bv YH &+ x׏ J +E t5 4 HՎ/w2TBH4=jgTF #* *\+.t /E]/E3~72898N޵mOOV5lXRu0[ V[d~`a.gcnyG*y$9y?. %+_%fn4sv;;j !ڕ(>d6S{w'¨²@CN^:n(,`$'rݖ rTcE n6RzrFCN7:5 Q  DlD1K2 ""#r!%4&%4P,--v0i)R01c1hw2wT=|s=e>k7F74MKL$.[m4 jb4rc5x;g3"]iCiTKl?pz3{`f{~a&}&?DhÓH$t[$0Oͣͣ#EwyN=m 8Szt-7ě45UȌ)Ȭ)mg rrܴ-1UC$B(~M6qt2 ,MOm*pfHi,0:@KBL 2:;04:C Close Tab CloseButton ?@>3@0<<5 %1About %1MAC_APPLICATION_MENU!:@KBL %1Hide %1MAC_APPLICATION_MENU!:@KBL 4@C385 Hide OthersMAC_APPLICATION_MENU0AB@>9:8...Preferences...MAC_APPLICATION_MENU025@H8BL %1Quit %1MAC_APPLICATION_MENU !;C61KServicesMAC_APPLICATION_MENU>:070BL 2AQShow AllMAC_APPLICATION_MENU*B:070=> 2 A>548=5=88Connection refusedQAbstractSocket6@5<O =0 A>548=5=85 8AB5:;>Connection timed outQAbstractSocket#75; =5 =0945=Host not foundQAbstractSocket!5BL =54>ABC?=0Network unreachableQAbstractSocketH?5@0F8O A A>:5B>< =5 ?>445@68205BAO$Operation on socket is not supportedQAbstractSocket$!>:5B =5 ?>4:;NGQ=Socket is not connectedQAbstractSocket,@5<O >?5@0F88 8AB5:;>Socket operation timed outQAbstractSocketR>?KB:0 ?>4:;NG8BLAO 2> 2@5<O ?>4:;NG5=8O1Trying to connect while connection is in progressQAbstractSocket&K45;8BL 2AQ &Select AllQAbstractSpinBox(03 22&5@E&Step upQAbstractSpinBox(03 2=&87 Step &downQAbstractSpinBox#<5=LH8BLDecreaseQAccessibleActionInterface$#<5=LH8BL 7=0G5=85Decrease the valueQAccessibleActionInterface#25;8G8BLIncreaseQAccessibleActionInterface$#25;8G8BL 7=0G5=85Increase the valueQAccessibleActionInterface 060BLPressQAccessibleActionInterface#AB0=>28BL$>:CASetFocusQAccessibleActionInterface #AB0=>28BL D>:CASets the focusQAccessibleActionInterface>:070BL5=NShowMenuQAccessibleActionInterface>:070BL <5=NShows the menuQAccessibleActionInterface!<5=8BLToggleQAccessibleActionInterface"!<5=8BL A>AB>O=85Toggles the stateQAccessibleActionInterface$K?>;=8BL 459AB285Triggers the actionQAccessibleActionInterface5BNoQAndroidPlatformTheme5B 4;O 2A5E No to AllQAndroidPlatformTheme0YesQAndroidPlatformTheme0 4;O 2A5E Yes to AllQAndroidPlatformThemej@>3@0<<5 %1 B@51C5BAO Qt %2, 0 8A?>;L7C5BAO Qt %3.,Executable '%1' requires Qt %2, found Qt %3. QApplicationDH81:0 A>2<5AB8<>AB8 181;8>B5:8 QtIncompatible Qt Library Error QApplication ?@>3@0<<5AboutQCocoaMenuItem QtAbout QtQCocoaMenuItem>=D83C@ConfigQCocoaMenuItem>?8@>20BLCopyQCocoaMenuItemK@570BLCutQCocoaMenuItem KE>4ExitQCocoaMenuItem0@0<5B@KOptionsQCocoaMenuItemAB028BLPasteQCocoaMenuItem!2>9AB2 PreferenceQCocoaMenuItem 025@HQuitQCocoaMenuItemK45;8BL 2AQ Select AllQCocoaMenuItem0AB@>9:SettingQCocoaMenuItem 0AB@SetupQCocoaMenuItem&5 A>E@0=OBL Don't Save QCocoaThemeF&>1028BL : ?>;L7>20B5;LA:8< F25B0<&Add to Custom Colors QColorDialog&A=>2=K5 F25B0 &Basic colors QColorDialog.&>;L7>20B5;LA:85 F25B0&Custom colors QColorDialog&5;Q=K9:&Green: QColorDialog &HTML:&HTML: QColorDialog&@0A=K9:&Red: QColorDialog &0A:&Sat: QColorDialog &/@::&Val: QColorDialog&;LD0-:0=0;:A&lpha channel: QColorDialog!&8=89:Bl&ue: QColorDialog`C@A>@ 2 %1, %2, F25B: %3 06<8B5 ESC 4;O >B<5=K/Cursor at %1, %2, color: %3 Press ESC to cancel QColorDialog &">=:Hu&e: QColorDialog&7OBL F25B A M:@0=0Pick Screen Color QColorDialogK1>@ F25B0 Select Color QColorDialog5BFalse QComboBox2B:@KBL 2K?040NI89 A?8A>:"Open the combo box selection popup QComboBox0True QComboBox@3C<5=BK: Arguments:QCommandLineParser.B>1@078BL MBC A?@02:C.Displays this help.QCommandLineParser>B>1@078BL 8=D>@<0F8N > 25@A88.Displays version information.QCommandLineParser@BACBAB2C5B 7=0G5=85 ?>A;5 %1.Missing value after '%1'.QCommandLineParser0@0<5B@K:Options:QCommandLineParser@5>6840==>5 7=0G5=85 ?>A;5 %1.Unexpected value after '%1'.QCommandLineParser458725AB=K9 ?0@0<5B@ %1.Unknown option '%1'.QCommandLineParser458725AB=K5 ?0@0<5B@K: %1.Unknown options: %1.QCommandLineParser"A?>;L7>20=85: %1 Usage: %1QCommandLineParser[?0@0<5B@K] [options]QCommandLineParser%1: >H81:0 ftok%1: ftok failedQCoreApplication%1: ?CAB>9 :;NG%1: key is emptyQCoreApplication6%1: =52>7<>6=> A>740BL :;NG%1: unable to make keyQCoreApplicationLTRQT_LAYOUT_DIRECTIONQCoreApplication@8D Banner PagesQCupsJobWidget*;0BQ6=0O 8=D>@<0F8O:Billing information:QCupsJobWidget&3@0=8G5==K9 4>ABC? ClassifiedQCupsJobWidget!5:@5B=> ConfidentialQCupsJobWidget,=Q< (A 6:00 ?> 17:59)Day (06:00 to 17:59)QCupsJobWidget :>=F5:End:QCupsJobWidgetB;>68BLHold IndefinitelyQCupsJobWidget040=85JobQCupsJobWidget#?@02;5=85 Job ControlQCupsJobWidget@8>@8B5B: Job priority:QCupsJobWidget.>GLN (A 18:00 ?> 5:59)Night (18:00 to 05:59)QCupsJobWidget5BNoneQCupsJobWidget"0?5G0B0BL A59G0APrint ImmediatelyQCupsJobWidget$B;>65==0O ?5G0BL:Scheduled printing:QCupsJobWidgetD> 2B>@CN A<5=C (A 16:00 ?> 23:59)Second Shift (16:00 to 23:59)QCupsJobWidget&!>25@H5==> A5:@5B=>SecretQCupsJobWidget( >?@545;Q==>5 2@5<O Specific TimeQCupsJobWidget!B0=40@B=0OStandardQCupsJobWidget =0G0;5:Start:QCupsJobWidget> B@5BLN A<5=C (A 0:00 ?> 7:59)Third Shift (00:00 to 07:59)QCupsJobWidgetA>1>9 206=>AB8 Top SecretQCupsJobWidget&B:@KB0O 8=D>@<0F8O UnclassifiedQCupsJobWidgetD 2KE>4=K5 (AC11>B0 8 2>A:@5A5=L5)Weekend (Saturday to Sunday)QCupsJobWidget>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transaction QDB2Driver,52>7<>6=> A>548=8BLAOUnable to connect QDB2Driver<52>7<>6=> >B:0B8BL B@0=70:F8NUnable to rollback transaction QDB2Driver^52>7<>6=> CAB0=>28BL 02B>7025@H5=85 B@0=70:F89Unable to set autocommit QDB2Driver:52>7<>6=> ?@82O70BL 7=0G5=85Unable to bind variable QDB2Result<52>7<>6=> 2K?>;=8BL 2K@065=85Unable to execute statement QDB2ResultB52>7<>6=> ?>;CG8BL ?5@2CN AB@>:CUnable to fetch first QDB2ResultH52>7<>6=> ?>;CG8BL A;54CNICN AB@>:CUnable to fetch next QDB2Result:52>7<>6=> ?>;CG8BL 70?8AL %1Unable to fetch record %1 QDB2Result@52>7<>6=> ?>43>B>28BL 2K@065=85Unable to prepare statement QDB2ResultAMAM QDateTimeEditPMPM QDateTimeEditamam QDateTimeEditpmpm QDateTimeEdit'B> MB>? What's This?QDialogOKOKQDialogButtonBox0B0 87<5=5=8O Date Modified QDirModel84Kind QDirModel<OName QDirModel  07<5@Size QDirModel"8?Type QDirModel"?5@0F8O >B<5=5=0Operation cancelled QDnsLookup@5 C40;>AL @0725@=CBL 8<O 4><5=0Could not expand domain nameQDnsLookupRunnable^4@5A0 IPv6 A5@25@>2 8<Q= 5IQ =5 ?>445@6820NBAO9IPv6 addresses for nameservers is currently not supportedQDnsLookupRunnable>5:>@@5:B=0O 70?8AL 04@5A0 IPv4Invalid IPv4 address recordQDnsLookupRunnable>5:>@@5:B=0O 70?8AL 04@5A0 IPv6Invalid IPv6 address recordQDnsLookupRunnableF5:>@@5:B=0O 70?8AL cannonical nameInvalid canonical name recordQDnsLookupRunnable.5:>@@5:B=>5 8<O 4><5=0Invalid domain nameQDnsLookupRunnable*5:>@@5:B=>5 8<O C7;0Invalid hostnameQDnsLookupRunnableB5:>@@5:B=0O 70?8AL mail exchangeInvalid mail exchange recordQDnsLookupRunnable>5:>@@5:B=0O 70?8AL name serverInvalid name server recordQDnsLookupRunnable65:>@@5:B=0O 70?8AL pointerInvalid pointer recordQDnsLookupRunnable4>;CG5= =5:>@@5:B=K9 >B25BInvalid reply receivedQDnsLookupRunnable65:>@@5:B=0O 70?8AL serviceInvalid service recordQDnsLookupRunnable05:>@@5:B=0O 70?8AL textInvalid text recordQDnsLookupRunnable&<O C7;0 =5 C:070=>No hostname givenQDnsLookupRunnable&><5= =5 ACI5AB2C5BNon existent domainQDnsLookupRunnableBIQ =5 ?>445@68205BAO ?>4 AndroidNot yet supported on AndroidQDnsLookupRunnableD$C=:F8O @07@5H5=8O 8<Q= =5 =0945=0Resolver functions not foundQDnsLookupRunnableV5 C40;>AL 8=8F80;878@>20BL @07@5H5=85 8<Q=Resolver initialization failedQDnsLookupRunnable5 C40;>AL 703@C78BL 181;8>B5:C 4;O @07@5H5=8O 8<Q=: 703@C7:0 181;8>B5: 2> 2@5<O @01>BK =5 ?>445@68205BAODResolver library can't be loaded: No runtime library loading supportQDnsLookupRunnable@!5@25@ =5 A<>3 >1@01>B0BL 70?@>AServer could not process queryQDnsLookupRunnableH81:0 A5@25@0Server failureQDnsLookupRunnable,!5@25@ >B:;>=8; 70?@>AServer refused to answerQDnsLookupRunnable0:@KBLClose QDockWidget 0:@K205B 28465BCloses the dock widget QDockWidget;020NI55Float QDockWidgetFBA>548=O5B 8 ?5@53@C??8@C5B 28465B'Undocks and re-attaches the dock widget QDockWidget&0:@KBL&OK QErrorMessageL&>:07K20BL MB> A>>1I5=85 2 40;L=59H5<&Show this message again QErrorMessage*B;04>G=>5 A>>1I5=85:Debug Message: QErrorMessage&@8B8G5A:0O >H81:0: Fatal Error: QErrorMessage@54C?@5645=85:Warning: QErrorMessage@52>7<>6=> A>740BL %1 4;O 2K2>40Cannot create %1 for outputQFile>52>7<>6=> >B:@KBL %1 4;O 22>40Cannot open %1 for inputQFile:52>7<>6=> >B:@KBL 4;O 2K2>40Cannot open for outputQFile@52>7<>6=> C40;8BL 8AE>4=K9 D09;Cannot remove source fileQFile$09; ACI5AB2C5BDestination file existsQFileR$09; =07=0G5=8O B0:>9 65, GB> 8 8AE>4=K9."Destination file is the same file.QFileF>7=8:;0 >H81:0 ?@8 ?5@58<5=>20=88.Error while renaming.QFile"!1>9 70?8A8 1;>:0Failure to write blockQFile4AE>4=K9 D09; >BACBAB2C5B.Source file does not exist.QFileB5 C40;>AL 2>AAB0=>28BL 87 %1: %2Unable to restore from %1: %2QFile>A;54>20B5;L=K9 D09; =5 1C45B ?5@58<5=>20= A 8A?>;L7>20=85< ?>1;>G=>3> :>?8@>20=8O0Will not rename sequential file using block copyQFilet5B D09;>2>3> 4286:0 8;8 >= =5 ?>445@68205B UnMapExtensionBNo file engine available or engine does not support UnMapExtension QFileDevice%1 0B0;>3 =5 =0945=. @>25@LB5 ?@028;L=>ABL C:070==>3> 8<5=8 :0B0;>30.K%1 Directory not found. Please verify the correct directory name was given. QFileDialog%1 $09; =5 =0945=. @>25@LB5 ?@028;L=>ABL C:070==>3> 8<5=8 D09;0.A%1 File not found. Please verify the correct file name was given. QFileDialog$09; %1%1 File QFileDialogN%1 C65 ACI5AB2C5B. %>B8B5 70<5=8BL 53>?-%1 already exists. Do you want to replace it? QFileDialog&K1@0BL&Choose QFileDialog&#40;8BL&Delete QFileDialog&>20O ?0?:0 &New Folder QFileDialog&B:@KBL&Open QFileDialog&5@58<5=>20BL&Rename QFileDialog&!>E@0=8BL&Save QFileDialogl%1 70I8IQ= >B 70?8A8. 59AB28B5;L=> 65;05B5 C40;8BL?9'%1' is write protected. Do you want to delete it anyway? QFileDialogA524>=8<Alias QFileDialogA5 D09;K (*) All Files (*) QFileDialogA5 D09;K (*) All files (*) QFileDialogAlt+LeftAlt+Left QFileDialogAlt+Right Alt+Right QFileDialog Alt+UpAlt+Up QFileDialog*5;05B5 C40;8BL %1?%Are you sure you want to delete '%1'? QFileDialog 0704Back QFileDialog:5@5:;NG8BL 2 ?>4@>1=K9 @568<Change to detail view mode QFileDialog45@5:;NG8BL 2 @568< A?8A:0Change to list view mode QFileDialog65 C40;>AL C40;8BL :0B0;>3.Could not delete directory. QFileDialog!>740BL ?0?:CCreate New Folder QFileDialog&!>740BL =>2CN ?0?:CCreate a New Folder QFileDialog#40;8BLDelete QFileDialog>4@>1=K9 284 Detail View QFileDialog0B0;>38 Directories QFileDialog0B0;>3: Directory: QFileDialog8A:Drive QFileDialog$09;File QFileDialog&<O D09;0: File &name: QFileDialog0?:0 A D09;0<8 File Folder QFileDialog $09;KFiles QFileDialog"8?K D09;>2:Files of type: QFileDialog09B8 :0B0;>3Find Directory QFileDialog 0?:0Folder QFileDialog ?5@Q4Forward QFileDialog 0704Go back QFileDialog ?5@Q4 Go forward QFileDialog<5@59B8 2 @>48B5;LA:89 :0B0;>3Go to the parent directory QFileDialog !?8A>: List View QFileDialog 5AB0 8 70:;04:8List of places and bookmarks QFileDialog5@59B8 ::Look in: QFileDialog>9 :><?LNB5@ My Computer QFileDialog>20O ?0?:0 New Folder QFileDialogB:@KBLOpen QFileDialog( >48B5;LA:89 :0B0;>3Parent Directory QFileDialog$5402=85 4>:C<5=BK Recent Places QFileDialog#40;8BLRemove QFileDialog!>E@0=8BL :0:Save As QFileDialog /@;K:Shortcut QFileDialog>:070BL Show  QFileDialog.>:070BL A:&@KBK5 D09;KShow &hidden files QFileDialog>:>20O ?0=5;LSidebar QFileDialog58725AB=K9Unknown QFileDialog %1 1%1 GBQFileSystemModel %1 1%1 KBQFileSystemModel %1 1%1 MBQFileSystemModel %1 "1%1 TBQFileSystemModel%1 109B %1 byte(s)QFileSystemModel%1 109B%1 bytesQFileSystemModel<b><O %1 =5 <>65B 1KBL 8A?>;L7>20=>.</b><p>>?@>1C9B5 8A?>;L7>20BL 8<O <5=LH59 4;8=K 8/8;8 157 A8<2>;>2 ?C=:BC0F88.oThe name "%1" can not be used.

      Try using another name, with fewer characters or no punctuations marks.QFileSystemModel><?LNB5@ComputerQFileSystemModel0B0 87<5=5=8O Date ModifiedQFileSystemModel,5:>@@5:B=>5 8<O D09;0Invalid filenameQFileSystemModel84KindQFileSystemModel>9 :><?LNB5@ My ComputerQFileSystemModel<ONameQFileSystemModel  07<5@SizeQFileSystemModel"8?TypeQFileSystemModel N10OAny QFontDatabase@01A:0OArabic QFontDatabase@<O=A:0OArmenian QFontDatabase5=30;LA:0OBengali QFontDatabase 'Q@=K9Black QFontDatabase 8@=K9Bold QFontDatabase8@8;;8F0Cyrillic QFontDatabase!@54=89Demi QFontDatabase>;C68@=K9 Demi Bold QFontDatabase520=038@8 Devanagari QFontDatabase@C78=A:0OGeorgian QFontDatabase@5G5A:0OGreek QFontDatabaseC460@0B8Gujarati QFontDatabaseC@<C:E8Gurmukhi QFontDatabase 2@8BHebrew QFontDatabase C@A82Italic QFontDatabase/?>=A:0OJapanese QFontDatabase0==040Kannada QFontDatabaseE<5@A:0OKhmer QFontDatabase>@59A:0OKorean QFontDatabase0>AA:0OLao QFontDatabase0B8=8F0Latin QFontDatabase!25B;K9Light QFontDatabase0;09O;0< Malayalam QFontDatabase LO=<0Myanmar QFontDatabase:>N'Ko QFontDatabase1KG=K9Normal QFontDatabase0:;>==K9Oblique QFontDatabase30<8G5A:0OOgham QFontDatabase@8OOriya QFontDatabase C=8G5A:0ORunic QFontDatabase(8B09A:0O C?@>IQ==0OSimplified Chinese QFontDatabase!8=30;LA:0OSinhala QFontDatabase!8<2>;L=0OSymbol QFontDatabase!8@89A:0OSyriac QFontDatabase"0<8;LA:0OTamil QFontDatabase "5;C3CTelugu QFontDatabase "00=0Thaana QFontDatabase"09A:0OThai QFontDatabase"815BA:0OTibetan QFontDatabase,8B09A:0O B@048F8>==0OTraditional Chinese QFontDatabaseL5B=0<A:0O Vietnamese QFontDatabase &(@8DB&Font QFontDialog& 07<5@&Size QFontDialog&>4GQ@:=CBK9 &Underline QFontDialog-DD5:BKEffects QFontDialog&0G5@B0=85 Font st&yle QFontDialog @8<5@Sample QFontDialogK1>@ H@8DB0 Select Font QFontDialog0GQ@&:=CBK9 Stri&keout QFontDialog&!8AB5<0 ?8AL<0Wr&iting System QFontDialog<5 C40;>AL A<5=8BL :0B0;>3: %1Changing directory failed: %1QFtpB#AB0=>2;5=> A>548=5=85 A C7;>< %1Connected to host %1QFtpD5 C40;>AL A>548=8BLAO A C7;><: %1Connecting to host failed: %1QFtp$!>548=5=85 70:@KB>Connection closedQFtp@ A>548=5=88 A C7;>< %1 >B:070=>Connection refused to host %1QFtpL@5<O =0 A>548=5=85 A C7;>< %1 8AB5:;>Connection timed out to host %1QFtp<5 C40;>AL A>740BL :0B0;>3: %1Creating directory failed: %1QFtpbB:;>=5=0 ?>?KB:0 ?>4:;NG5=8O 4;O ?5@540G8 40==KEData Connection refusedQFtp:5 C40;>AL 703@C78BL D09;: %1Downloading file failed: %1QFtp"#75; %1 =5 =0945=Host %1 not foundQFtp@5 C40;>AL ?@>G8B0BL :0B0;>3: %1Listing directory failed: %1QFtp:5 C40;>AL 02B>@87>20BLAO: %1Login failed: %1QFtp2!>548=5=85 =5 CAB0=>2;5=> Not connectedQFtp<5 C40;>AL C40;8BL :0B0;>3: %1Removing directory failed: %1QFtp65 C40;>AL C40;8BL D09;: %1Removing file failed: %1QFtp$58725AB=0O >H81:0 Unknown errorQFtp:5 C40;>AL >B3@C78BL D09;: %1Uploading file failed: %1QFtpB&<5=0&Cancel QGnomeTheme&0:@KBL&Close QGnomeTheme&OK&OK QGnomeTheme&!>E@0=8BL&Save QGnomeTheme,0:@KBL 157 A>E@0=5=8OClose without Saving QGnomeTheme$<O C7;0 =5 7040=>No host name given QHostInfo$58725AB=0O >H81:0 Unknown error QHostInfo#75; =5 =0945=Host not foundQHostInfoAgent*5:>@@5:B=>5 8<O C7;0Invalid hostnameQHostInfoAgent$<O C7;0 =5 7040=>No host name givenQHostInfoAgent,58725AB=K9 B8? 04@5A0Unknown address typeQHostInfoAgent$58725AB=0O >H81:0 Unknown errorQHostInfoAgent.58725AB=0O >H81:0 (%1)Unknown error (%1)QHostInfoAgent$!>548=5=85 70:@KB>Connection closedQHttp*B:070=> 2 A>548=5=88Connection refusedQHttp"0==K5 ?>2@5645=KData corruptedQHttp"#75; %1 =5 =0945=Host %1 not foundQHttp0#75; B@51C5B 02B>@870F8NHost requires authenticationQHttpF@5<O =0 >?5@0F8N A A>:5B>< 8AB5:;>Proxy requires authenticationQHttp628B8@>20=85 SSL =5 C40;>ALSSL handshake failedQHttp6#:070= =58725AB=K9 ?@>B>:>;Unknown protocol specifiedQHttp*"@51C5BAO 02B>@870F8OAuthentication requiredQHttpSocketEngineN5 ?>;CG5= HTTP->B25B >B ?@>:A8-A5@25@0(Did not receive HTTP response from proxyQHttpSocketEngineXH81:0 >1<5=0 40==K<8 A ?@>:A8-A5@25@>< HTTP#Error communicating with HTTP proxyQHttpSocketEnginehH81:0 @071>@0 70?@>A0 02B>@870F88 >B ?@>:A8-A5@25@0/Error parsing authentication request from proxyQHttpSocketEngine^!>548=5=85 A ?@>:A8-A5@25@>< =5>6840==> 70:@KB>#Proxy connection closed prematurelyQHttpSocketEngineJ A>548=5=88 ?@>:A8-A5@25@>< >B:070=>Proxy connection refusedQHttpSocketEngineB@>:A8-A5@25@ 70?@5B8; A>548=5=85Proxy denied connectionQHttpSocketEngineZ@5<O =0 A>548=5=85 A ?@>:A8-A5@25@>< 8AB5:;>!Proxy server connection timed outQHttpSocketEngine.@>:A8-A5@25@ =5 =0945=Proxy server not foundQHttpSocketEngine85 C40;>AL =0G0BL B@0=70:F8NCould not start transaction QIBaseDriver6H81:0 >B:@KB8O 107K 40==KEError opening database QIBaseDriver>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transaction QIBaseDriver<52>7<>6=> >B:0B8BL B@0=70:F8NUnable to rollback transaction QIBaseDriverd5 C40;>AL ?>;CG8BL @5AC@AK 4;O A>740=8O 2K@065=8OCould not allocate statement QIBaseResultJ5 C40;>AL >?8A0BL 2E>4OI55 2K@065=85"Could not describe input statement QIBaseResult85 C40;>AL >?8A0BL 2K@065=85Could not describe statement QIBaseResultJ5 C40;>AL ?>;CG8BL A;54CNI89 M;5<5=BCould not fetch next item QIBaseResult.5 C40;>AL =09B8 <0AA82Could not find array QIBaseResult>5 C40;>AL =09B8 40==K5 <0AA820Could not get array data QIBaseResultJ5 C40;>AL =09B8 8=D>@<0F8N > 70?@>A5Could not get query info QIBaseResultN5 C40;>AL =09B8 8=D>@<0F8N > 2K@065=88Could not get statement info QIBaseResult@5 C40;>AL ?>43>B>28BL 2K@065=85Could not prepare statement QIBaseResult85 C40;>AL =0G0BL B@0=70:F8NCould not start transaction QIBaseResult852>7<>6=> 70:@KBL 2K@065=85Unable to close statement QIBaseResult>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transaction QIBaseResult.52>7<>6=> A>740BL BLOBUnable to create BLOB QIBaseResult652>7<>6=> 2K?>;=8BL 70?@>AUnable to execute query QIBaseResult.52>7<>6=> >B:@KBL BLOBUnable to open BLOB QIBaseResult252>7<>6=> ?@>G8B0BL BLOBUnable to read BLOB QIBaseResult052>7<>6=> 70?8A0BL BLOBUnable to write BLOB QIBaseResultD5B A2>1>4=>3> <5AB0 =0 CAB@>9AB25No space left on device QIODevice<$09; 8;8 :0B0;>3 =5 ACI5AB2C5BNo such file or directory QIODevice>ABC? 70?@5IQ=Permission denied QIODevice:!;8H:>< <=>3> >B:@KBKE D09;>2Too many open files QIODevice$58725AB=0O >H81:0 Unknown error QIODeviceF>B:@K205<K9 D09; O2;O5BAO :0B0;>3><file to open is a directory QIODevice$09; =5 =0945=File not found QImageReader.5:>@@5:B=>5 CAB@>9AB2>Invalid device QImageReaderN5 C40;>AL ?@>G8B0BL 40==K5 87>1@065=8OUnable to read image data QImageReader$58725AB=0O >H81:0 Unknown error QImageReaderF5?>445@68205<K9 D>@<0B 87>1@065=8OUnsupported image format QImageReader(#AB@>9AB2> =5 7040=>Device is not set QImageWriterB#AB@>9AB2> =5 ?>445@68205B 70?8ALDevice not writable QImageWriter$58725AB=0O >H81:0 Unknown error QImageWriterF5?>445@68205<K9 D>@<0B 87>1@065=8OUnsupported image format QImageWriter"#:068B5 7=0G5=85:Enter a value: QInputDialog.<CA>@ 2 :>=F5 4>:C<5=B0"garbage at the end of the documentQJsonParseError$=5:>@@5:B=>5 G8A;>illegal numberQJsonParseError*=54>?CAB8<>5 7=0G5=85 illegal valueQJsonParseErrorH=5:>@@5:B=0O ?>A;54>20B5;L=>ABL UTF8invalid UTF8 stringQJsonParseErrorF=5:>@@5:B=0O ESC-?>A;54>20B5;L=>ABLinvalid escape sequenceQJsonParseError<=5:>@@5:B=>5 7025@H5=85 G8A;><invalid termination by numberQJsonParseError8>BACBAB2C5B @0745;8B5;L 8<Q=missing name separatorQJsonParseError@>BACBAB2C5B @0745;8B5;L 7=0G5=89missing value separatorQJsonParseError$>H81:8 >BACBAB2CNBno error occurredQJsonParseError<>BACBAB2C5B >1J5:B ?>A;5 B>G:8object is missing after a commaQJsonParseErrorV4>:C<5=B 8<55B A;8H:>< 3;C1>:CN 2;>65==>ABLtoo deeply nested documentQJsonParseError0A;8H:>< 1>;LH>9 4>:C<5=Btoo large documentQJsonParseError(=57025@HQ==K9 <0AA82unterminated arrayQJsonParseError(57025@HQ==K9 >1J5:Bunterminated objectQJsonParseError(=57025@HQ==0O AB@>:0unterminated stringQJsonParseError%1, ...%1, ...QKeySequenceEdit006<8B5 A>G5B0=85 :;028HPress shortcutQKeySequenceEditX%1 O2;O5BAO =5:>@@5:B=K< >1J5:B>< ELF (%2)"'%1' is an invalid ELF object (%2)QLibrary"%1 =5 ?;038= Qt'%1' is not a Qt pluginQLibraryN%1 =525@=K9 18=0@=K9 D09; Mach-O (%2)&'%1' is not a valid Mach-O binary (%2)QLibrary:%1 =5 O2;O5BAO >1J5:B>< ELF'%1' is not an ELF objectQLibraryD%1 =5 O2;O5BAO >1J5:B>< ELF (%2)'%1' is not an ELF object (%2)QLibraryL52>7<>6=> 703@C78BL 181;8>B5:C %1: %2Cannot load library %1: %2QLibraryR52>7<>6=> @07@5H8BL A8<2>; %1 2 %2: %3$Cannot resolve symbol "%1" in %2: %3QLibraryL52>7<>6=> 2K3@C78BL 181;8>B5:C %1: %2Cannot unload library %1: %2QLibraryf@>25@>G=0O 8=D>@<0F8O 4;O <>4C;O %1 =5 A>2?0405B)Plugin verification data mismatch in '%1'QLibrary\$09; %1  =5 O2;O5BAO :>@@5:B=K< <>4C;5< Qt.'The file '%1' is not a valid Qt plugin.QLibrary>4C;L %1 8A?>;L7C5B =5A><5AB8<CN 181;8>B5:C Qt. (%2.%3.%4) [%5]=The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]QLibrary>4C;L %1 8A?>;L7C5B =5A><5AB8<CN 181;8>B5:C Qt. (52>7<>6=> A>2<5AB8BL @5;87=K5 8 >B;04>G=K5 181;8>B5:8.)WThe plugin '%1' uses incompatible Qt library. (Cannot mix debug and release libraries.)QLibraryF8=0<8G5A:0O 181;8>B5:0 =5 =0945=0.!The shared library was not found.QLibrary$58725AB=0O >H81:0 Unknown errorQLibraryD09; ?>2@564Q=file is corruptQLibrary D09; A;8H:>< <0;file too smallQLibrary2=525@=K9 845=B8D8:0B>@ %1invalid magic %1QLibraryD=5B ?>4E>4OI59 0@E8B5:BC@K 2 D09;5&no suitable architecture in fat binaryQLibrary4=5 48=0<8G5A:0O 181;8>B5:0not a dynamic libraryQLibrary(=525@=0O 0@E8B5:BC@0wrong architectureQLibrary&>?8@>20BL&Copy QLineEdit&AB028BL&Paste QLineEdit&&>2B>@8BL 459AB285&Redo QLineEdit$&B<5=8BL 459AB285&Undo QLineEdit&K@570BLCu&t QLineEdit#40;8BLDelete QLineEditK45;8BL 2AQ Select All QLineEdit,%1: 4@5A 8A?>;L7C5BAO%1: Address in use QLocalServer(%1: 5:>@@5:B=>5 8<O%1: Name error QLocalServer&%1: >ABC? 70?@5IQ=%1: Permission denied QLocalServer2%1: 58725AB=0O >H81:0 %2%1: Unknown error %2 QLocalServer&%1: >ABC? 70?@5IQ=%1: Access denied QLocalSocket*%1: H81:0 A>548=5=8O%1: Connection error QLocalSocket2%1: B:070=> 2 A>548=5=88%1: Connection refused QLocalSocket<%1: 0B03@0<<0 A;8H:>< 1>;LH0O%1: Datagram too large QLocalSocket(%1: 5:>@@5:B=>5 8<O%1: Invalid name QLocalSocketn%1: ?5@0F8O =5 @07@5H5=0, :>340 A>:5B 2 MB>< A>AB>O=888%1: Operation not permitted when socket is in this state QLocalSocket<%1: 0:@KB> C40;5==>9 AB>@>=>9%1: Remote closed QLocalSocket:%1: H81:0 >1@0I5=8O : A>:5BC%1: Socket access error QLocalSocketN%1: @5<O =0 >?5@0F8N A A>:5B>< 8AB5:;>%1: Socket operation timed out QLocalSocketH%1: H81:0 2K45;5=8O @5AC@A>2 A>:5B0%1: Socket resource error QLocalSocketP%1: ?5@0F8O A A>:5B>< =5 ?>445@68205BAO)%1: The socket operation is not supported QLocalSocket,%1: 58725AB=0O >H81:0%1: Unknown error QLocalSocket2%1: 58725AB=0O >H81:0 %2%1: Unknown error %2 QLocalSocketR>?KB:0 ?>4:;NG8BLAO 2> 2@5<O ?>4:;NG5=8O1Trying to connect while connection is in progress QLocalSocket852>7<>6=> =0G0BL B@0=70:F8NUnable to begin transaction QMYSQLDriver>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transaction QMYSQLDriver,52>7<>6=> A>548=8BLAOUnable to connect QMYSQLDriverF52>7<>6=> >B:@KBL 107C 40==KE %1Unable to open database '%1' QMYSQLDriver<52>7<>6=> >B:0B8BL B@0=70:F8NUnable to rollback transaction QMYSQLDriverX52>7<>6=> ?@82O70BL @57C;LB8@CNI85 7=0G5=8OUnable to bind outvalues QMYSQLResult:52>7<>6=> ?@82O70BL 7=0G5=85Unable to bind value QMYSQLResultJ52>7<>6=> 2K?>;=8BL A;54CNI89 70?@>AUnable to execute next query QMYSQLResult652>7<>6=> 2K?>;=8BL 70?@>AUnable to execute query QMYSQLResult<52>7<>6=> 2K?>;=8BL 2K@065=85Unable to execute statement QMYSQLResult452>7<>6=> ?>;CG8BL 40==K5Unable to fetch data QMYSQLResult@52>7<>6=> ?>43>B>28BL 2K@065=85Unable to prepare statement QMYSQLResult:52>7<>6=> A1@>A8BL 2K@065=85Unable to reset statement QMYSQLResultP52>7<>6=> A>E@0=8BL A;54CNI89 @57C;LB0BUnable to store next result QMYSQLResult<52>7<>6=> A>E@0=8BL @57C;LB0BUnable to store result QMYSQLResulth52>7<>6=> A>E@0=8BL @57C;LB0BK 2K?>;=5=8O 2K@065=8O!Unable to store statement results QMYSQLResult(5>703;02;5=>) (Untitled)QMdiArea%1 - [%2] %1 - [%2] QMdiSubWindow&0:@KBL&Close QMdiSubWindow&5@5<5AB8BL&Move QMdiSubWindow&>AAB0=>28BL&Restore QMdiSubWindow& 07<5@&Size QMdiSubWindow - [%1]- [%1] QMdiSubWindow0:@KBLClose QMdiSubWindow!?@02:0Help QMdiSubWindow &0A?0E=CBL Ma&ximize QMdiSubWindow 0A?0E=CBLMaximize QMdiSubWindow5=NMenu QMdiSubWindow&!25@=CBL Mi&nimize QMdiSubWindow!25@=CBLMinimize QMdiSubWindow>AAB0=>28BLRestore QMdiSubWindow>AAB0=>28BL Restore Down QMdiSubWindow(!25@=CBL 2 703>;>2>:Shade QMdiSubWindow$AB020BLAO &A25@EC Stay on &Top QMdiSubWindow2>AAB0=>28BL 87 703>;>2:0Unshade QMdiSubWindowz<h3> Qt</h3><p>0==0O ?@>3@0<<0 8A?>;L7C5B Qt 25@A88 %1.</p>8

      About Qt

      This program uses Qt version %1.

       QMessageBox l<p>Qt  MB> 8=AB@C<5=B0@89 4;O @07@01>B:8 :@>AA?;0BD>@<5==KE ?@8;>65=89 =0 C++.</p><p>Qt ?@54>AB02;O5B A>2<5AB8<>ABL =0 C@>2=5 8AE>4=KE B5:AB>2 <564C 4;O 2A5E ?>?C;O@=KE =0AB>;L=KE >?5@0F8>==KE A8AB5<. "0:65 Qt 4>ABC?=0 4;O 2AB@08205<>3> Linux 8 4@C38E <>18;L=KE >?5@0F8>==KE A8AB5<.</p><p>Qt 4>ABC?=0 ?>4 B@5<O @07;8G=K<8 ;8F5=78O<8, @07@01>B0==K<8 4;O C4>2;5B2>@5=8O B@51>20=89 @07=KE ?>;L7>20B5;59.</p><p>Qt ?>4 =0H59 :><<5@G5A:>9 ;8F5=7859 ?@54=07=0G5=0 4;O @0728B8O ?@>?@85B0@=>3>/:><<5@G5A:>3> ?@>3@0<<=>3> >15A?5G5=8O, :>340 =5B 65;0=8O/ ?@54>AB02;OBL 8AE>4=K5 B5:ABK B@5BL8< ;8F0< 2 A;CG05 =52>7<>6=>AB8 ?@8=OB8O CA;>289 ;8F5=789 GNU LGPL 25@A88 3 8;8 GNU LGPL 25@A88 2.1.</p><p>Qt ?>4 ;8F5=7859 GNU LGPL 25@A88 3 ?@54=07=0G5=0 4;O @07@01>B:8 ?@>3@0<<=>3> >15A?5G5=8O C4>2;5B2>@ONI53> B@51>20=8O< ;8F5=788 GNU LGPL 25@A88 3.</p><p>Qt ?>4 ;8F5=7859 GNU LGPL 25@A88 2.1 ?@54=07=0G5=0 4;O @07@01>B:8 ?@>3@0<<=>3> >15A?5G5=8O C4>2;5B2>@ONI53> B@51>20=8O< ;8F5=788 GNU LGPL 25@A88 2.1.</p><p>>4@>1=55 A CA;>28O<8 ;8F5=78@>20=8O Qt <>6=> >7=0:><8BLAO =0 A09B5 <a href="http://%2/">%2</a>.</p><p>Copyright (C) %1 Digia Plc 8/8;8 5Q 4>G5@=85 ?>4@0745;5=8O 8 4@C385 CG0AB=8:8.</p><p>Qt, :0: >B:@KBK9 ?@>5:B, @07@010BK205BAO =0 <a href="http://qt-project.org/">qt-project.org</a>.</p><p>Qt  ?@>4C:B :><?0=88 Digia, @07@010BK205<K9 2 :0G5AB25 ?@>5:B0 A >B:@KBK<8 8AE>4=K<8 B5:AB0<8. >;55 ?>4@>1=CN 8=D>@<0F8N <>6=> =09B8 =0 A09B5 <a href="http://%3/">%3</a>.</p>c

      Qt is a C++ toolkit for cross-platform application development.

      Qt provides single-source portability across all major desktop operating systems. It is also available for embedded Linux and other embedded and mobile operating systems.

      Qt is available under three different licensing options designed to accommodate the needs of our various users.

      Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 3 or GNU LGPL version 2.1.

      Qt licensed under the GNU LGPL version 3 is appropriate for the development of Qt applications provided you can comply with the terms and conditions of the GNU LGPL version 3.

      Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt applications provided you can comply with the terms and conditions of the GNU LGPL version 2.1.

      Please see %2 for an overview of Qt licensing.

      Copyright (C) %1 Digia Plc and/or its subsidiary(-ies) and other contributors.

      Qt and the Qt logo are trademarks of Digia Plc and/or its subsidiary(-ies).

      Qt is a Digia product developed as an open source project. See %3 for more information.

       QMessageBox QtAbout Qt QMessageBox!?@02:0Help QMessageBox*!:@KBL ?>4@>1=>AB8...Hide Details... QMessageBox0:@KBLOK QMessageBox.>:070BL ?>4@>1=>AB8...Show Details... QMessageBoxN@C3>9 A>:5B C65 ?@>A;CH8205B MB>B ?>@B4Another socket is already listening on the same portQNativeSocketEngine|>?KB:0 8A?>;L7>20BL IPv6 =0 ?;0BD>@<5, =5 ?>445@6820NI59 IPv6=Attempt to use IPv6 socket on a platform with no IPv6 supportQNativeSocketEngine*B:070=> 2 A>548=5=88Connection refusedQNativeSocketEngine6@5<O =0 A>548=5=85 8AB5:;>Connection timed outQNativeSocketEngineN0B03@0<<0 A;8H:>< 1>;LH0O 4;O >B?@02:8Datagram was too large to sendQNativeSocketEngine#75; =54>ABC?5=Host unreachableQNativeSocketEngine<5:>@@5:B=K9 45A:@8?B>@ A>:5B0Invalid socket descriptorQNativeSocketEngineH81:0 A5B8 Network errorQNativeSocketEngineB@5<O =0 A5B52CN >?5@0F8N 8AB5:;>Network operation timed outQNativeSocketEngine!5BL =54>ABC?=0Network unreachableQNativeSocketEngine*?5@0F8O A =5-A>:5B><Operation on non-socketQNativeSocketEngine*54>AB0B>G=> @5AC@A>2Out of resourcesQNativeSocketEngine>ABC? 70?@5IQ=Permission deniedQNativeSocketEngine4@>B>:>; =5 ?>445@68205BAOProtocol type not supportedQNativeSocketEngine @5<5==0O >H81:0Temporary errorQNativeSocketEngine 4@5A =54>ABC?5=The address is not availableQNativeSocketEngine4@5A 70I8IQ=The address is protectedQNativeSocketEngine,4@5A C65 8A?>;L7C5BAO#The bound address is already in useQNativeSocketEnginef5:>@@5:B=K9 B8? ?@>:A8-A5@25@0 4;O 40==>9 >?5@0F88,The proxy type is invalid for this operationQNativeSocketEngine@#40;Q==K9 C75; 70:@K; A>548=5=85%The remote host closed the connectionQNativeSocketEnginef52>7<>6=> 8=8F80;878@>20BL H8@>:>25I0B5;L=K9 A>:5B%Unable to initialize broadcast socketQNativeSocketEngineX52>7<>6=> 8=8F80;878@>20BL =5-1;>G=K9 A>:5B(Unable to initialize non-blocking socketQNativeSocketEngine:52>7<>6=> ?>;CG8BL A>>1I5=85Unable to receive a messageQNativeSocketEngine<52>7<>6=> >B?@028BL A>>1I5=85Unable to send a messageQNativeSocketEngine&52>7<>6=> 70?8A0BLUnable to writeQNativeSocketEngine$58725AB=0O >H81:0 Unknown errorQNativeSocketEngineH?5@0F8O A A>:5B>< =5 ?>445@68205BAOUnsupported socket operationQNativeSocketEngine$H81:0 >B:@KB8O %1Error opening %1QNetworkAccessCacheBackend(5:>@@5:B=K9 URI: %1Invalid URI: %1QNetworkAccessDataBackendf#40;Q==K9 C75; =5>6840==> ?@5@20; A>548=5=85 4;O %13Remote host closed the connection prematurely on %1QNetworkAccessDebugPipeBackend.H8:0 A>:5B0 4;O %1: %2Socket error on %1: %2QNetworkAccessDebugPipeBackend,H81:0 70?8A8 2 %1: %2Write error writing to %1: %2QNetworkAccessDebugPipeBackendZ52>7<>6=> >B:@KBL %1: #:070= ?CBL : :0B0;>3C#Cannot open %1: Path is a directoryQNetworkAccessFileBackend,H81:0 >B:@KB8O %1: %2Error opening %1: %2QNetworkAccessFileBackend.H81:0 GB5=8O 87 %1: %2Read error reading from %1: %2QNetworkAccessFileBackend`0?@>A =0 >B:@KB85 D09;0 2=5 D09;>2>9 A8AB5<K %1%Request for opening non-local file %1QNetworkAccessFileBackend,H81:0 70?8A8 2 %1: %2Write error writing to %1: %2QNetworkAccessFileBackendZ52>7<>6=> >B:@KBL %1: #:070= ?CBL : :0B0;>3CCannot open %1: is a directoryQNetworkAccessFtpBackendBH81:0 2 ?@>F5AA5 703@C7:8 %1: %2Error while downloading %1: %2QNetworkAccessFtpBackendBH81:0 2 ?@>F5AA5 >B3@C7:8 %1: %2Error while uploading %1: %2QNetworkAccessFtpBackendb!>548=5=85 A %1 =5 C40;>AL: B@51C5BAO 02B>@870F8O0Logging in to %1 failed: authentication requiredQNetworkAccessFtpBackendD>4E>4OI89 ?@>:A8-A5@25@ =5 =0945=No suitable proxy foundQNetworkAccessFtpBackend.>ABC? 2 A5BL >B:;NGQ=.Network access is disabled.QNetworkAccessManager8$>=>2K5 70?@>AK =54>?CAB8<K.Background request not allowed. QNetworkReplyLH81:0 703@C7:8 %1  >B25B A5@25@0: %2)Error downloading %1 - server replied: %2 QNetworkReply,H81:0 A5B52>9 A5AA88.Network session error. QNetworkReply258725AB=K9 ?@>B>:>; %1Protocol "%1" is unknown QNetworkReply,@5<5==0O >H81:0 A5B8.Temporary network failure. QNetworkReply0>H81:0 70?CA:0 4@0925@0.backend start error. QNetworkReplyD>4E>4OI89 ?@>:A8-A5@25@ =5 =0945=No suitable proxy foundQNetworkReplyHttpImpl"?5@0F8O >B<5=5=0Operation canceledQNetworkReplyHttpImpl"?5@0F8O >B<5=5=0Operation canceledQNetworkReplyImpl45:>@@5:B=0O :>=D83C@0F8O.Invalid configuration.QNetworkSession> >C<8=3 ?@5@20= 8;8 =52>7<>65=.'Roaming was aborted or is not possible.QNetworkSessionPrivateImpl\"@51C5<0O >?5@0F8O =5 ?>445@68205BAO A8AB5<>9.7The requested operation is not supported by the system.QNetworkSessionPrivateImpl`!5AA8O 1K;0 ?@5@20=0 ?>;L7>20B5;5< 8;8 A8AB5<>9..The session was aborted by the user or system.QNetworkSessionPrivateImpl^52>7<>6=> 8A?>;L7>20BL C:070==CN :>=D83C@0F8N.+The specified configuration cannot be used.QNetworkSessionPrivateImpl458725AB=0O >H81:0 A5AA88.Unknown session error.QNetworkSessionPrivateImpl852>7<>6=> =0G0BL B@0=70:F8NUnable to begin transaction QOCIDriver>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transaction QOCIDriver652>7<>6=> 8=8F80;878@>20BLUnable to initialize QOCIDriver252>7<>6=> 02B>@87>20BLAOUnable to logon QOCIDriver<52>7<>6=> >B:0B8BL B@0=70:F8NUnable to rollback transaction QOCIDriver852>7<>6=> A>740BL 2K@065=85Unable to alloc statement QOCIResultj52>7<>6=> ?@82O70BL AB>;15F 4;O ?0:5B=>3> 2K?>;=5=8O'Unable to bind column for batch execute QOCIResultX52>7<>6=> ?@82O70BL @57C;LB8@CNI85 7=0G5=8OUnable to bind value QOCIResultN52>7<>6=> 2K?>;=8BL ?0:5B=>5 2K@065=85!Unable to execute batch statement QOCIResult<52>7<>6=> 2K?>;=8BL 2K@065=85Unable to execute statement QOCIResultF52>7<>6=> >?@545;8BL B8? 2K@065=8OUnable to get statement type QOCIResultJ52>7<>6=> ?5@59B8 : A;54CNI59 AB@>:5Unable to goto next QOCIResult@52>7<>6=> ?>43>B>28BL 2K@065=85Unable to prepare statement QOCIResult>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transaction QODBCDriver,52>7<>6=> A>548=8BLAOUnable to connect QODBCDriver52>7<>6=> A>548=8BLAO  @0925@ =5 ?>445@68205B B@51C5<K9 DC=:F8>=0;EUnable to connect - Driver doesn't support all functionality required QODBCDriver\52>7<>6=> >B:;NG8BL 02B>7025@H5=85 B@0=70:F89Unable to disable autocommit QODBCDriverZ52>7<>6=> 2:;NG8BL 02B>7025@H5=85 B@0=70:F89Unable to enable autocommit QODBCDriver<52>7<>6=> >B:0B8BL B@0=70:F8NUnable to rollback transaction QODBCDriverQODBCResult::reset: 52>7<>6=> CAB0=>28BL SQL_CURSOR_STATIC 0B@81CB>< 2K@065=85. @>25@LB5 =0AB@>9:8 4@0925@0 ODBCyQODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration QODBCResult:52>7<>6=> ?@82O70BL 7=0G5=85Unable to bind variable QODBCResult<52>7<>6=> 2K?>;=8BL 2K@065=85Unable to execute statement QODBCResult452>7<>6=> ?>;CG8BL 40==K5Unable to fetch QODBCResultB52>7<>6=> ?>;CG8BL ?5@2CN AB@>:CUnable to fetch first QODBCResultH52>7<>6=> ?>;CG8BL ?>A;54=NN AB@>:CUnable to fetch last QODBCResultH52>7<>6=> ?>;CG8BL A;54CNICN AB@>:CUnable to fetch next QODBCResultJ52>7<>6=> ?>;CG8BL ?@54K4CICN AB@>:CUnable to fetch previous QODBCResult@52>7<>6=> ?>43>B>28BL 2K@065=85Unable to prepare statement QODBCResult85 C40;>AL =0G0BL B@0=70:F8NCould not begin transaction QPSQLDriver>5 C40;>AL 7025@H8BL B@0=70:F8NCould not commit transaction QPSQLDriver<5 C40;>AL >B:0B8BL B@0=70:F8NCould not rollback transaction QPSQLDriver,52>7<>6=> A>548=8BLAOUnable to connect QPSQLDriver,52>7<>6=> ?>4?8A0BLAOUnable to subscribe QPSQLDriver*52>7<>6=> >B?8A0BLAOUnable to unsubscribe QPSQLDriver252>7<>6=> A>740BL 70?@>AUnable to create query QPSQLResult@52>7<>6=> ?>43>B>28BL 2K@065=85Unable to prepare statement QPSQLResultCCCCQPageSetupWidget&8F5@> (CC) Cicero (CC)QPageSetupWidget A>1K9CustomQPageSetupWidgetDDDDQPageSetupWidget84> (DD) Didot (DD)QPageSetupWidget $>@<0FormQPageSetupWidgetKA>B0:Height:QPageSetupWidgetN9<K (4<) Inches (in)QPageSetupWidget;L1><=0O LandscapeQPageSetupWidget>;OMarginsQPageSetupWidget8;;8<5B@K (<<)Millimeters (mm)QPageSetupWidget@85=B0F8O OrientationQPageSetupWidget$ 07<5I5=85 AB@0=8F Page LayoutQPageSetupWidget >@O4>: AB@0=8F: Page order:QPageSetupWidget  07<5@ AB@0=8FK: Page size:QPageSetupWidget"!B@0=8F =0 ;8AB5:Pages per sheet:QPageSetupWidget C<030PaperQPageSetupWidget AB>G=8: 1C<038: Paper source:QPageSetupWidget8:0 (P8) Pica (P̸)QPageSetupWidget">G:8 (?B) Points (pt)QPageSetupWidget=86=0OPortraitQPageSetupWidgetP8P̸QPageSetupWidget,5@52Q@=CB0O 0;L1><=0OReverse landscapeQPageSetupWidget(5@52Q@=CB0O :=86=0OReverse portraitQPageSetupWidget(8@8=0:Width:QPageSetupWidget=86=55 ?>;5 bottom marginQPageSetupWidget4<inQPageSetupWidget;52>5 ?>;5 left marginQPageSetupWidget<<mmQPageSetupWidget?BptQPageSetupWidget?@02>5 ?>;5 right marginQPageSetupWidget25@E=55 ?>;5 top marginQPageSetupWidget%1 x %2 4< %1 x %2 in QPageSizeA0A0 QPageSizeA1A1 QPageSizeA10A10 QPageSizeA2A2 QPageSizeA3A3 QPageSizeA3 ExtraA3 Extra QPageSizeA4A4 QPageSizeA4 ExtraA4 Extra QPageSizeA4 PlusA4 Plus QPageSizeA4 SmallA4 Small QPageSizeA5A5 QPageSizeA5 ExtraA5 Extra QPageSizeA6A6 QPageSizeA7A7 QPageSizeA8A8 QPageSizeA9A9 QPageSize ANSI CANSI C QPageSize ANSI DANSI D QPageSize ANSI EANSI E QPageSizeArchitect A Architect A QPageSizeArchitect B Architect B QPageSizeArchitect C Architect C QPageSizeArchitect D Architect D QPageSizeArchitect E Architect E QPageSizeB0B0 QPageSizeB1B1 QPageSizeB10B10 QPageSizeB2B2 QPageSizeB3B3 QPageSizeB4B4 QPageSizeB5B5 QPageSizeB5 ExtraB5 Extra QPageSizeB6B6 QPageSizeB7B7 QPageSizeB8B8 QPageSizeB9B9 QPageSize A>1K9Custom QPageSize,A>1K9 (%1 CC x %2 CC)Custom (%1CC x %2CC) QPageSize,A>1K9 (%1 DD x %2 DD)Custom (%1DD x %2DD) QPageSize,A>1K9 (%1 4< x %2 4<)Custom (%1in x %2in) QPageSize,A>1K9 (%1 << x %2 <<)Custom (%1mm x %2mm) QPageSize,A>1K9 (%1 P8 x %2 P8)Custom (%1pc x %2pc) QPageSize,A>1K9 (%1 ?B x %2 ?B)Custom (%1pt x %2pt) QPageSizeDouble PostcardDouble Postcard QPageSizeEnvelope B4 Envelope B4 QPageSizeEnvelope B5 Envelope B5 QPageSizeEnvelope B6 Envelope B6 QPageSizeEnvelope C0 Envelope C0 QPageSizeEnvelope C1 Envelope C1 QPageSizeEnvelope C2 Envelope C2 QPageSizeEnvelope C3 Envelope C3 QPageSizeEnvelope C4 Envelope C4 QPageSizeEnvelope C5 Envelope C5 QPageSizeEnvelope C6 Envelope C6 QPageSizeEnvelope C65 Envelope C65 QPageSizeEnvelope C7 Envelope C7 QPageSizeEnvelope Chou 3Envelope Chou 3 QPageSizeEnvelope Chou 4Envelope Chou 4 QPageSizeEnvelope DL Envelope DL QPageSizeEnvelope InviteEnvelope Invite QPageSize Envelope ItalianEnvelope Italian QPageSizeEnvelope Kaku 2Envelope Kaku 2 QPageSizeEnvelope Kaku 3Envelope Kaku 3 QPageSize Envelope MonarchEnvelope Monarch QPageSizeEnvelope PRC 1Envelope PRC 1 QPageSizeEnvelope PRC 10Envelope PRC 10 QPageSizeEnvelope PRC 2Envelope PRC 2 QPageSizeEnvelope PRC 3Envelope PRC 3 QPageSizeEnvelope PRC 4Envelope PRC 4 QPageSizeEnvelope PRC 5Envelope PRC 5 QPageSizeEnvelope PRC 6Envelope PRC 6 QPageSizeEnvelope PRC 7Envelope PRC 7 QPageSizeEnvelope PRC 8Envelope PRC 8 QPageSizeEnvelope PRC 9Envelope PRC 9 QPageSize"Envelope PersonalEnvelope Personal QPageSizeEnvelope US 10Envelope US 10 QPageSizeEnvelope US 11Envelope US 11 QPageSizeEnvelope US 12Envelope US 12 QPageSizeEnvelope US 14Envelope US 14 QPageSizeEnvelope US 9 Envelope US 9 QPageSizeEnvelope You 4Envelope You 4 QPageSize4Executive (7.25 x 10.5 4<)Executive (7.25 x 10.5 in) QPageSize.Executive (7.5 x 10 4<)Executive (7.5 x 10 in) QPageSize:Fan-fold German (8.5 x 12 in)Fan-fold German (8.5 x 12 in) QPageSizeFFan-fold German Legal (8.5 x 13 in)#Fan-fold German Legal (8.5 x 13 in) QPageSize8Fan-fold US (14.875 x 11 in)Fan-fold US (14.875 x 11 in) QPageSize(Folio (8.27 x 13 4<)Folio (8.27 x 13 in) QPageSize JIS B0JIS B0 QPageSize JIS B1JIS B1 QPageSizeJIS B10JIS B10 QPageSize JIS B2JIS B2 QPageSize JIS B3JIS B3 QPageSize JIS B4JIS B4 QPageSize JIS B5JIS B5 QPageSize JIS B6JIS B6 QPageSize JIS B7JIS B7 QPageSize JIS B8JIS B8 QPageSize JIS B9JIS B9 QPageSizeLedger / ANSI BLedger / ANSI B QPageSize LegalLegal QPageSizeLegal Extra Legal Extra QPageSizeLetter / ANSI ALetter / ANSI A QPageSizeLetter Extra Letter Extra QPageSizeLetter Plus Letter Plus QPageSizeLetter Small Letter Small QPageSizeNoteNote QPageSizePRC 16KPRC 16K QPageSizePRC 32KPRC 32K QPageSizePRC 32K Big PRC 32K Big QPageSizePostcardPostcard QPageSize QuartoQuarto QPageSizeStatement Statement QPageSizeSuper ASuper A QPageSizeSuper BSuper B QPageSize Tabloid / ANSI BTabloid / ANSI B QPageSizeTabloid Extra Tabloid Extra QPageSize&5B&NoQPlatformTheme&0&YesQPlatformTheme@5@20BLAbortQPlatformTheme@8<5=8BLApplyQPlatformTheme B<5=0CancelQPlatformTheme0:@KBLCloseQPlatformThemeB:;>=8BLDiscardQPlatformTheme!?@02:0HelpQPlatformTheme@>?CAB8BLIgnoreQPlatformTheme&5B 4;O 2A5E N&o to AllQPlatformThemeOKOKQPlatformThemeB:@KBLOpenQPlatformTheme!1@>A8BLResetQPlatformTheme> C<>;G0=8NRestore DefaultsQPlatformTheme>2B>@8BLRetryQPlatformTheme!>E@0=8BLSaveQPlatformTheme!>E@0=8BL 2A5Save AllQPlatformTheme0 4;O &2A5E Yes to &AllQPlatformTheme.>4C;L =5 1K; 703@C65=.The plugin was not loaded. QPluginLoader$58725AB=0O >H81:0 Unknown error QPluginLoaderN%1 C65 ACI5AB2C5B. %>B8B5 70<5=8BL 53>?/%1 already exists. Do you want to overwrite it? QPrintDialogX%1  MB> :0B0;>3. K15@8B5 4@C3>5 8<O D09;0.7%1 is a directory. Please choose a different file name. QPrintDialog&0@0<5B@K << &Options << QPrintDialog&0@0<5B@K >> &Options >> QPrintDialog&5G0BL&Print QPrintDialog1 (1x1)1 (1x1) QPrintDialog16 (4x4)16 (4x4) QPrintDialog2 (2x1)2 (2x1) QPrintDialog4 (2x2)4 (2x2) QPrintDialog6 (2x3)6 (2x3) QPrintDialog9 (3x3)9 (3x3) QPrintDialogA5 AB@0=8FK All Pages QPrintDialog2B><0B8G5A:8 Automatic QPrintDialog4!=87C 225@E, A;520 =0?@02>Bottom to Top, Left to Right QPrintDialog4!=87C 225@E, A?@020 =0;52>Bottom to Top, Right to Left QPrintDialog 'QB=K5 Even Pages QPrintDialogh%1 =54>ABC?5= 4;O 70?8A8. K15@8B5 4@C3>5 8<O D09;0.=File %1 is not writable. Please choose a different file name. QPrintDialog4!;520 =0?@02>, A=87C 225@ELeft to Right, Bottom to Top QPrintDialog4!;520 =0?@02>, A25@EC 2=87Left to Right, Top to Bottom QPrintDialog>:0;L=K9 D09; Local file QPrintDialogOKOK QPrintDialog5GQB=K5 Odd Pages QPrintDialog0@0<5B@K !B@0=8F =0 ;8AB5 8 !?8A>: AB@0=8F =5 <>3CB 8A?>;L7>20BLAO >4=>2@5<5==>. K:;NG8B5 >48= 87 =8E.gOptions 'Pages Per Sheet' and 'Page Set' cannot be used together. Please turn one of those options off. QPrintDialog 5G0BLPrint QPrintDialog"5G0BL 2 D09; ...Print To File ... QPrintDialog&5G0BL 2 D09; (PDF)Print to File (PDF) QPrintDialog4!?@020 =0;52>, A=87C 225@ERight to Left, Bottom to Top QPrintDialog4!?@020 =0;52>, A25@EC 2=87Right to Left, Top to Bottom QPrintDialog`=0G5=85 A =5 <>65B 1KBL 1>;LH5 7=0G5=8O ?>.7The 'From' value cannot be greater than the 'To' value. QPrintDialog4!25@EC 2=87, A;520 =0?@02>Top to Bottom, Left to Right QPrintDialog4!25@EC 2=87, A?@020 =0;52>Top to Bottom, Right to Left QPrintDialog0?8AL D09; PDFWrite PDF file QPrintDialog%1%%1%QPrintPreviewDialog-:A?>@B 2 PDF Export to PDFQPrintPreviewDialog5@20O AB@0=8F0 First pageQPrintPreviewDialog0 2AN AB@0=8FCFit pageQPrintPreviewDialog> H8@8=5 Fit widthQPrintPreviewDialog;L1><=0O LandscapeQPrintPreviewDialog$>A;54=OO AB@0=8F0 Last pageQPrintPreviewDialog$!;54CNI0O AB@0=8F0 Next pageQPrintPreviewDialog$0@0<5B@K AB@0=8FK Page SetupQPrintPreviewDialog$0@0<5B@K AB@0=8FK Page setupQPrintPreviewDialog=86=0OPortraitQPrintPreviewDialog&@54K4CI0O AB@0=8F0 Previous pageQPrintPreviewDialog 5G0BLPrintQPrintPreviewDialog@>A<>B@ ?5G0B8 Print PreviewQPrintPreviewDialog6>:070BL B8BC;L=K5 AB@0=8FKShow facing pagesQPrintPreviewDialog6>:070BL >17>@ 2A5E AB@0=8FShow overview of all pagesQPrintPreviewDialog,>:070BL >4=C AB@0=8FCShow single pageQPrintPreviewDialog#25;8G8BLZoom inQPrintPreviewDialog#<5=LH8BLZoom outQPrintPreviewDialog"0@0<5B@K 7040=8O Job OptionsQPrintPropertiesDialog $>@<0FormQPrintPropertiesWidget!B@0=8F0PageQPrintPropertiesWidget& 07>1@0BL ?> :>?8O<CollateQPrintSettingsOutput&25BColorQPrintSettingsOutput 568< F25B0 Color ModeQPrintSettingsOutput >?88CopiesQPrintSettingsOutput">;8G5AB2> :>?89:Copies:QPrintSettingsOutput "5:CI0O AB@0=8F0 Current PageQPrintSettingsOutput&2CAB>@>==OO ?5G0BLDuplex PrintingQPrintSettingsOutput $>@<0FormQPrintSettingsOutputBB5=:8 A5@>3> GrayscaleQPrintSettingsOutput$> 4;8==>9 AB>@>=5 Long sideQPrintSettingsOutput5BNoneQPrintSettingsOutput0@0<5B@KOptionsQPrintSettingsOutput 0AB@>9:8 2K2>40Output SettingsQPrintSettingsOutput!?8A>: AB@0=8F: Page Set:QPrintSettingsOutput!B@0=8FK A Pages fromQPrintSettingsOutputA5 Print allQPrintSettingsOutput80?07>= ?5G0B8 Print rangeQPrintSettingsOutput 1@0B=K9 ?>@O4>:ReverseQPrintSettingsOutput&K45;5==K9 D@03<5=B SelectionQPrintSettingsOutput&> :>@>B:>9 AB>@>=5 Short sideQPrintSettingsOutput?>toQPrintSettingsOutput&0720=85:&Name: QPrintWidget...... QPrintWidget $>@<0Form QPrintWidget 0A?>;>65=85: Location: QPrintWidgetK2>4 2 &D09;: Output &file: QPrintWidget!&2>9AB20 P&roperties QPrintWidget@>A<>B@Preview QPrintWidget@8=B5@Printer QPrintWidget"8?:Type: QPrintWidgetf5 C40;>AL >B:@KBL ?5@5=0?@02;5=85 22>40 4;O GB5=8O,Could not open input redirection for readingQProcessh5 C40;>AL >B:@KBL ?5@5=0?@02;5=85 2K2>40 4;O 70?8A8-Could not open output redirection for writingQProcessFH81:0 ?>;CG5=8O 40==KE >B ?@>F5AA0Error reading from processQProcess>H81:0 >B?@02:8 40==KE ?@>F5AACError writing to processQProcess(@>3@0<<0 =5 C:070=0No program definedQProcess8@>F5AA 7025@H8;AO A >H81:>9Process crashedQProcess@5 C40;>AL 70?CAB8BL ?@>F5AA: %1Process failed to start: %1QProcessJ@5<O =0 >?5@0F8N A ?@>F5AA>< 8AB5:;>Process operation timed outQProcessRH81:0 2K45;5=8O @5AC@A>2 (A1>9 fork): %1!Resource error (fork failure): %1QProcessB<5=8BLCancelQProgressDialogA5 D09;K (*.*)All files (*.*)QQnxFileDialogHelper"",CANCELQQnxFileDialogHelperOKOKQQnxFileDialogHelperK1>@ D09;0 Pick a fileQQnxFilePickerL=5?@028;L=K9 A8=B0:A8A :;0AA0 A8<2>;>2bad char class syntaxQRegExp@=5?@028;L=K9 A8=B0:A8A lookaheadbad lookahead syntaxQRegExpB=5?@028;L=K9 A8=B0:A8A ?>2B>@5=8Obad repetition syntaxQRegExpL8A?>;L7>20=85 >B:;NGQ==KE 2>7<>6=>AB59disabled feature usedQRegExp,=5:>@@5:B=0O :0B53>@8Oinvalid categoryQRegExp*=5:>@@5:B=K9 8=B5@20;invalid intervalQRegExpD=5:>@@5:B=>5 2>AL<5@8G=>5 7=0G5=85invalid octal valueQRegExpXlookbehind =5 ?>445@68205BAO, A<. QTBUG-2371)lookbehinds not supported, see QTBUG-2371QRegExpB4>AB83=CB> 2=CB@5==55 >3@0=8G5=85met internal limitQRegExp:>BACBAB2C5B ;52K9 @0745;8B5;Lmissing left delimQRegExp$>H81:8 >BACBAB2CNBno error occurredQRegExp"=5>6840==K9 :>=5Funexpected endQRegExp:(*MARK) 4>;65= 8<5BL 0@3C<5=B(*MARK) must have an argumentQRegularExpression$(*VERB) =5 >?>7=0=(*VERB) not recognizedQRegularExpressionR70 (?R 8;8 (?[+-]F8D@K 4>;6=0 A;54>20BL ))(?R or (?[+-]digits must be followed by )QRegularExpressionP3@C??0 DEFINE A>45@68B 1>;55 >4=>9 25B:8*DEFINE group contains more than one branchQRegularExpressionZPCRE =5 ?>445@68205B \L, \l, \N{8<O}, \U 8 \u1PCRE does not support \L, \l, \N{name}, \U, or \uQRegularExpressionXPOSIX-A>@B8@>2:0 M;5<5=B>2 =5 ?>445@68205BAO*POSIX collating elements are not supportedQRegularExpression:;0AAK 8<5=>20==K5 2 AB8;5 POSIX ?>445@6820NBAO B>;L:> 2=CB@8 :;0AA05POSIX named classes are supported only within a classQRegularExpression"\ 2 :>=F5 H01;>=0\ at end of patternQRegularExpressionJ\C =5 4>?CAB8<0 2 ?@>25@:5 lookbehind&\C not allowed in lookbehind assertionQRegularExpression:\N =5 ?>445@68205BAO 2 :;0AA5\N is not supported in a classQRegularExpression$\c 2 :>=F5 H01;>=0\c at end of patternQRegularExpressionL?>A;5 \c 4>;65= A;54>20BL A8<2>; ASCII)\c must be followed by an ASCII characterQRegularExpression70 \g 4>;6=> A;54>20BL G8A;> 8;8 =0720=85/G8A;> 70:;NGQ==>5 2 D83C@=K5/C3;>2K5 A:>1:8 8;8 :02KG:8[\g is not followed by a braced, angle-bracketed, or quoted name/number or by a plain numberQRegularExpression70 \k 4>;6=> A;54>20BL =0720=85 70:;NGQ==>5 2 D83C@=K5/C3;>2K5 A:>1:8 8;8 :02KG:8?\k is not followed by a braced, angle-bracketed, or quoted nameQRegularExpression] =54>?CAB8<K9 A8<2>; 40==KE 2 @568<5 A>2<5AB8<>AB8 A JavaScript?] is an invalid data character in JavaScript compatibility modeQRegularExpressionP=C<5@>20==0O AAK;:0 =5 4>;6=0 1KBL =C;Q<%a numbered reference must not be zeroQRegularExpressionr4;O (*ACCEPT), (*FAIL) 8 (*COMMIT) 0@3C<5=BK =5 4>?CAB8<K?an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)QRegularExpression8?>A;5 (?( B@51C5BAO ?@>25@:0assertion expected after (?(QRegularExpressiont7=0G5=85 A8<2>;0 2 ?>A;54>20B5;L=>AB8 \u... A;8H:>< 25;8:>/character value in \u.... sequence is too largeQRegularExpressionz7=0G5=85 A8<2>;0 2 ?>A;54>20B5;L=>AB8 \x{...} A;8H:>< 1>;LH>50character value in \x{...} sequence is too largeQRegularExpression>B@51C5BAO 70:@K20NI0O ) 4;O (?Cclosing ) for (?C expectedQRegularExpressionRCA;>2=0O 3@C??0 A>45@68B 1>;55 42CE 25B>:1conditional group contains more than two branchesQRegularExpressionv>B;8G=K5 8<5=0 4;O ?>4H01;>=>2 A >4=8< =><5@>< =5 4>?CAB8<KBdifferent names for subpatterns of the same number are not allowedQRegularExpression2?>A;5 (?+ B@51C5BAO F8D@0digit expected after (?+QRegularExpressionv=54>?CAB8<0O :>4>20O B>G:0 Unicode (>= 0xd800 && <= 0xdfff)6disallowed Unicode code point (>= 0xd800 && <= 0xdfff)QRegularExpressionB2 :0G5AB25 erroffset ?5@540= NULLerroffset passed as NULLQRegularExpression4=5 C40;>AL 2K45;8BL ?0<OBLfailed to get memoryQRegularExpressionL8<O 3@C??K 4>;6=> =0G8=0BLAO A =5F8D@K&group name must start with a non-digitQRegularExpression6=5A>2<5AB8<0O >?F8O NEWLINEinconsistent NEWLINE optionsQRegularExpressionH2=CB@5==OO >H81:0: ?5@5?>;=5=85 :>40internal error: code overflowQRegularExpressionl2=CB@5==OO >H81:0: 2KE>4 70 ?@545;K >1;0AB8 :><?8;OF88+internal error: overran compiling workspaceQRegularExpressionp2=CB@5==OO >H81:0: @0=55 ?@>25@5==K9 ?>4H01;>= =5 =0945=Binternal error: previously-checked referenced subpattern not foundQRegularExpressionJ2=CB@5==OO >H81:0: =5>6840==K9 ?>2B>@!internal error: unexpected repeatQRegularExpressionr2=CB@5==OO >H81:0: =58725AB=K9 >?:>4 2 find_fixedlength()4internal error: unknown opcode in find_fixedlength()QRegularExpression4=5:>@@5:B=0O AB@>:0 UTF-16invalid UTF-16 stringQRegularExpression4=5:>@@5:B=0O AB@>:0 UTF-32invalid UTF-32 stringQRegularExpression2=5:>@@5:B=0O AB@>:0 UTF-8invalid UTF-8 stringQRegularExpression4=5:>@@5:B=>5 CA;>285 (?(0)invalid condition (?(0)QRegularExpressionj=5:>@@5:B=0O ESC-?>A;54>20B5;L=>ABL 2 :;0AA5 A8<2>;>2*invalid escape sequence in character classQRegularExpressionN=54>?CAB8<K9 480?07>= 2 :;0AA5 A8<2>;>2 invalid range in character classQRegularExpression^?@>25@:0 lookbehind 8<55B =5D8:A8@>20==CN 4;8=C(lookbehind assertion is not fixed lengthQRegularExpressionj=5:>@@5:B=> AD>@<8@>20=0 ?>A;54>20B5;L=>ABL \P 8;8 \pmalformed \P or \p sequenceQRegularExpression`=5:>@@5:B=> AD>@<8@>20=> G8A;> 8;8 8<O ?>A;5 (?("malformed number or name after (?(QRegularExpression>BACBAB2C5B ) missing )QRegularExpression>>BACBAB2C5B ) ?>A;5 :><<5=B0@8Omissing ) after commentQRegularExpression`>BACBAB2C5B >B:@K20NI0O D83C@=0O A:>1:0 ?>A;5 \omissing opening brace after \oQRegularExpressionZ>BACBAB2C5B 7025@H0NI0O ] 4;O :;0AA0 A8<2>;>2)missing terminating ] for character classQRegularExpressionxA;8H:>< 4;8==>5 8<O 2 (*MARK), (*PRUNE), (*SKIP) 8;8 (*THEN):name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)QRegularExpression=5B >H81:8no errorQRegularExpression=5-H5AB=04F0B5@8G=K9 A8<2>; 2 \x {} (>BACBAB2C5B 70:@K20NI0O A:>1:0?)2non-hex character in \x{} (closing brace missing?)QRegularExpression=5-2>AL<5@8G=K9 A8<2>; 2 \o {} (>BACBAB2C5B 70:@K20NI0O A:>1:0?)4non-octal character in \o{} (closing brace missing?)QRegularExpression =5G53> ?>2B>@OBLnothing to repeatQRegularExpression4G8A;> ?>A;5 (?C 1>;LH5 255number after (?C is > 255QRegularExpression(G8A;> A;8H:>< 25;8:>number is too bigQRegularExpressionNG8A;> A;8H:>< 25;8:> 2 :20;8D8:0B>@5 {}number too big in {} quantifierQRegularExpressionJ=5:>@@5:B=K5 G8A;0 2 :20;8D8:0B>@5 {}%numbers out of order in {} quantifierQRegularExpressiond2>AL<8@8G=>5 G8A;> 1>;LH5 \377 (2 @568<5 =5 UTF-8)4octal value is greater than \377 (not in UTF-8 mode)QRegularExpression>A;8H:>< 1>;LH>5 2;>65=85 A:>1>:!parentheses are too deeply nestedQRegularExpression`A;8H:>< 1>;LH>5 2;>65=85 A:>1>: (:>=B@>;L AB5:0)/parentheses are too deeply nested (stack check)QRegularExpressionN=5:>@@5:B=K9 480?07>= 2 :;0AA5 A8<2>;>2%range out of order in character classQRegularExpressionV@5:C@A82=K9 2K7>2 <>65B 70F8:;8BLAO =025G=>&recursive call could loop indefinitelyQRegularExpressionDAAK;:0 =0 =5ACI5AB2CNI89 ?>4H01;>=$reference to non-existent subpatternQRegularExpressionF 53C;O@=>5 2K@065=85 A;8H:>< 25;8:>regular expression is too largeQRegularExpression@?>2B>@ 3@C??K DEFINE =5 4>?CAB8<'repeating a DEFINE group is not allowedQRegularExpressionF=0AB@>9:0 UTF >B:;NG5=0 ?@8;>65=85<*setting UTF is disabled by the applicationQRegularExpression0B@51C5BAO 8<O ?>4H01;>=0subpattern name expectedQRegularExpressionx=0720=85 ?>4H01;>=0 A;8H:>< 25;8:> (>3@0=8G5=> 2 32 A8<2>;0)3subpattern name is too long (maximum 32 characters)QRegularExpressionN?>445@6:0 \P, \p 8 \X =5 A:><?8;8@>20=00support for \P, \p, and \X has not been compiledQRegularExpressionA8=B0:A8G5A:0O >H81:0 2 8<5=8 ?>4H01;>=0 (>BACBAB2C5B ?@87=0: 7025@H5=8O)4syntax error in subpattern name (missing terminator)QRegularExpression\MB0 25@A8O PCRE A>1@0=0 157 ?>445@6:8 PCRE_UCP:this version of PCRE is not compiled with PCRE_UCP supportQRegularExpression^MB0 25@A8O PCRE A>1@0=0 157 ?>445@6:8 PCRE_UTF8;this version of PCRE is not compiled with PCRE_UTF8 supportQRegularExpression@A;8H:>< <=>3> >?5@560NI8E AAK;>:too many forward referencesQRegularExpressionnA;8H:>< <=>3> 8<5=>20=KE ?>4H01;>=>2 (>3@0=8G5=> 10000)*too many named subpatterns (maximum 10000)QRegularExpression^420 8<5=>20==KE ?>4H01;>=0 8<5NB >48=0:>2>5 8<O(two named subpatterns have the same nameQRegularExpression8=58725AB=>5 8<O POSIX :;0AA0unknown POSIX class nameQRegularExpression\=58725AB=K9 =01>@ D;03>2 @53C;O@=>3> 2K@065=8Ounknown option bit(s) setQRegularExpressionP=58725AB=>5 8<O A2>9AB20 ?>A;5 \P 8;8 \p$unknown property name after \P or \pQRegularExpression::@C3;K5 A:>1:8 =5 A>3;0A>20=Kunmatched parenthesesQRegularExpressionRA8<2>; A;54CNI89 70 (? 8;8 (?- =5 >?>7=0=&unrecognized character after (? or (?-QRegularExpression6A8<2>; ?>A;5 (?< =5 >?>7=0= unrecognized character after (?<QRegularExpression6A8<2>; ?>A;5 (?P =5 >?>7=0= unrecognized character after (?PQRegularExpression@A8<2>; A;54CNI89 70 \ =5 >?>7=0= unrecognized character follows \QRegularExpression6H81:0 >B:@KB8O 107K 40==KEError opening databaseQSQLite2Driver852>7<>6=> =0G0BL B@0=70:F8NUnable to begin transactionQSQLite2Driver>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transactionQSQLite2Driver<52>7<>6=> >B:0B8BL B@0=70:F8NUnable to rollback transactionQSQLite2Driver<52>7<>6=> 2K?>;=8BL 2K@065=85Unable to execute statementQSQLite2Result<52>7<>6=> ?>;CG8BL @57C;LB0BKUnable to fetch resultsQSQLite2Result6H81:0 70:@KB8O 107K 40==KEError closing database QSQLiteDriver6H81:0 >B:@KB8O 107K 40==KEError opening database QSQLiteDriver852>7<>6=> =0G0BL B@0=70:F8NUnable to begin transaction QSQLiteDriver>52>7<>6=> 7025@H8BL B@0=70:F8NUnable to commit transaction QSQLiteDriver<52>7<>6=> >B:0B8BL B@0=70:F8NUnable to rollback transaction QSQLiteDriver$BACBAB2C5B 70?@>ANo query QSQLiteResultD>;8G5AB2> ?0@0<5B@>2 =5 A>2?0405BParameter count mismatch QSQLiteResult:52>7<>6=> ?@82O70BL ?0@0<5B@Unable to bind parameters QSQLiteResultl52>7<>6=> >4=>2@5<5==> 70?CAB8BL =5A:>;L:> >?5@0B>@>2/Unable to execute multiple statements at a time QSQLiteResult<52>7<>6=> 2K?>;=8BL 2K@065=85Unable to execute statement QSQLiteResult452>7<>6=> ?>;CG8BL AB@>:CUnable to fetch row QSQLiteResult:52>7<>6=> A1@>A8BL 2K@065=85Unable to reset statement QSQLiteResultP!CI5AB2CNI89 D09; %1 70I8IQ= >B 70?8A8 Existing file %1 is not writable QSaveFile<<O D09;0 AAK;05BAO =0 :0B0;>3Filename refers to a directory QSaveFile60?8AL ?@5@20=0 ?@8;>65=85<Writing canceled by application QSaveFile=87Bottom QScrollBar ;52>9 3@0=8F5 Left edge QScrollBar 0 AB@0=8FC 2=87 Page down QScrollBar"0 AB@0=8FC 2;52> Page left QScrollBar$0 AB@0=8FC 2?@02> Page right QScrollBar"0 AB@0=8FC 225@EPage up QScrollBar  ?@02>9 3@0=8F5 Right edge QScrollBar@>:@CB8BL 2=87 Scroll down QScrollBar@>:@CB8BL AN40 Scroll here QScrollBar @>:@CB8BL 2;52> Scroll left QScrollBar"@>:@CB8BL 2?@02> Scroll right QScrollBar @>:@CB8BL 225@E Scroll up QScrollBar 25@ETop QScrollBarR%1: A?5F8D8G5A:89 :;NG UNIX =5 ACI5AB2C5B%1: UNIX key file doesn't exist QSharedMemory$%1: C65 ACI5AB2C5B%1: already exists QSharedMemory,%1: @07<5@ <5=LH5 =C;O%1: create size is less then 0 QSharedMemory"%1: =5 ACI5AB2C5B%1: doesn't exist QSharedMemory%1: >H81:0 ftok%1: ftok failed QSharedMemory.%1: =54>?CAB8<K9 @07<5@%1: invalid size QSharedMemory %1: >H81:0 :;NG0 %1: key error QSharedMemory%1: ?CAB>9 :;NG%1: key is empty QSharedMemory$%1: =5 ?@8;>65==K9%1: not attached QSharedMemory2%1: =54>AB0B>G=> @5AC@A>2%1: out of resources QSharedMemory&%1: 4>ABC? 70?@5IQ=%1: permission denied QSharedMemory>%1: =5 C40;>AL 70?@>A8BL @07<5@%1: size query failed QSharedMemoryV%1: A8AB5<>9 =0;>65=K >3@0=8G5=8O =0 @07<5@$%1: system-imposed size restrictions QSharedMemory8%1: =52>7<>6=> 701;>:8@>20BL%1: unable to lock QSharedMemory6%1: =52>7<>6=> A>740BL :;NG%1: unable to make key QSharedMemoryR%1: =52>7<>6=> CAB0=>28BL :;NG 1;>:8@>2:8%1: unable to set key on lock QSharedMemory:%1: =52>7<>6=> @071;>:8@>20BL%1: unable to unlock QSharedMemory2%1: =58725AB=0O >H81:0 %2%1: unknown error %2 QSharedMemory++ QShortcut(>1028BL 2 871@0==>5 Add Favorite QShortcut"0AB@>9:0 O@:>AB8Adjust Brightness QShortcutAltAlt QShortcut"520O A>DB-:=>?:0Application Left QShortcut$@020O A>DB-:=>?:0Application Right QShortcutF0F8:;5==>5 2>A?@>872545=85 4>@>6:8Audio Cycle Track QShortcut2!;CG09=>5 2>A?@>872545=85Audio Random Play QShortcut0>A?@>872545=85 ?> :@C3C Audio Repeat QShortcut#HQ;Away QShortcut 0704Back QShortcut0704/2?5@Q4 Back Forward QShortcutBackspace Backspace QShortcutBacktabBacktab QShortcut#A8;5=85 10A>2 Bass Boost QShortcut0AK =865 Bass Down QShortcut0AK 2KH5Bass Up QShortcut0B0@5OBattery QShortcut>;C10OBlue QShortcutBluetooth Bluetooth QShortcut =830Book QShortcut1>7@520B5;LBrowser QShortcutCDCD QShortcut0;L:C;OB>@ Calculator QShortcut>72>=8BLCall QShortcut$$>:CA8@>2:0 :0<5@K Camera Focus QShortcut0B2>@ :0<5@KCamera Shutter QShortcut B<5=0Cancel QShortcut5@=89 @538AB@ Caps Lock QShortcutCapsLockCapsLock QShortcut0=0; 2=87 Channel Down QShortcut0=0; 225@E Channel Up QShortcutG8AB8BLClear QShortcutG8AB8BL 70E20B Clear Grab QShortcut0:@KBLClose QShortcut2>4 :>40 Code input QShortcut!>>1I5AB2> Community QShortcut>?8@>20BLCopy QShortcutCtrlCtrl QShortcutK@570BLCut QShortcutDOSDOS QShortcutDelDel QShortcut#40;8BLDelete QShortcutDisplayDisplay QShortcut>:C<5=BK Documents QShortcut=87Down QShortcut72;5GLEject QShortcutEndEnd QShortcut EnterEnter QShortcutEscEsc QShortcut EscapeEscape QShortcutK?>;=8BLExecute QShortcut KE>4Exit QShortcutF%1F%1 QShortcut71@0==>5 Favorites QShortcut$8=0=AKFinance QShortcut 09B8Find QShortcut @KH:0Flip QShortcut ?5@Q4Forward QShortcut3@0Game QShortcut5@59B8Go QShortcut5;Q=0OGreen QShortcut ><>ILGuide QShortcut B1>9Hangup QShortcutHelpHelp QShortcut#AK?8BL Hibernate QShortcutAB>@8OHistory QShortcutHomeHome QShortcut><0H=89 >D8A Home Office QShortcut"><0H=OO AB@0=8F0 Home Page QShortcut>@OG85 AAK;:8 Hot Links QShortcut=D>@<0F8OInfo QShortcutInsIns QShortcutAB028BLInsert QShortcutL#<5=LH8BL O@:>ABL ?>4A25B:8 :;0280BC@KKeyboard Brightness Down QShortcutL#25;8G8BL O@:>ABL ?>4A25B:8 :;0280BC@KKeyboard Brightness Up QShortcut>:;./>B:;. ?>4A25B:C :;0280BC@KKeyboard Light On/Off QShortcut";0280BC@=>5 <5=N Keyboard Menu QShortcut>2B>@=K9 =01>@Last Number Redial QShortcut0?CAB8BL (0) Launch (0) QShortcut0?CAB8BL (1) Launch (1) QShortcut0?CAB8BL (2) Launch (2) QShortcut0?CAB8BL (3) Launch (3) QShortcut0?CAB8BL (4) Launch (4) QShortcut0?CAB8BL (5) Launch (5) QShortcut0?CAB8BL (6) Launch (6) QShortcut0?CAB8BL (7) Launch (7) QShortcut0?CAB8BL (8) Launch (8) QShortcut0?CAB8BL (9) Launch (9) QShortcut0?CAB8BL (A) Launch (A) QShortcut0?CAB8BL (B) Launch (B) QShortcut0?CAB8BL (C) Launch (C) QShortcut0?CAB8BL (D) Launch (D) QShortcut0?CAB8BL (E) Launch (E) QShortcut0?CAB8BL (F) Launch (F) QShortcut >GB0 Launch Mail QShortcut@>83@K20B5;L Launch Media QShortcut ;52>Left QShortcut0<?>G:0 LightBulb QShortcut K9B8 87 A8AB5<KLogoff QShortcut 5@5A;0BL ?8AL<> Mail Forward QShortcut  K=>:Market QShortcut.#A:>@5==>5 ?@>83@K20=85Media Fast Forward QShortcut.>A?@>8725AB8 A;54CNI55 Media Next QShortcut:@8>AB0=>28BL 2>A?@>872545=85 Media Pause QShortcut,0G0BL 2>A?@>872545=85 Media Play QShortcut0>A?@>8725AB8 ?@54K4CI55Media Previous QShortcut0G0BL 70?8AL Media Record QShortcut&5@5<>B0BL 2 =0G0;> Media Rewind QShortcut4AB0=>28BL 2>A?@>872545=85 Media Stop QShortcutAB@5G0Meeting QShortcutMenuMenu QShortcutJ;85=B >1<5=0 <3=>25==K<8 A>>1I5=8O<8 Messenger QShortcutMetaMeta QShortcut$K:;NG8BL <8:@>D>=Microphone Mute QShortcut:#<5=LH8BL 3@><:>ABL <8:@>D>=0Microphone Volume Down QShortcut:#25;8G8BL 3@><:>ABL <8:@>D>=0Microphone Volume Up QShortcut4#<5=LH8BL O@:>ABL <>=8B>@0Monitor Brightness Down QShortcut4#25;8G8BL O@:>ABL <>=8B>@0Monitor Brightness Up QShortcut&5A:>;L:> 20@80=B>2Multiple Candidate QShortcut C7K:0Music QShortcut>8 A09BKMy Sites QShortcut!>740BLNew QShortcut>2>AB8News QShortcut5BNo QShortcutNumNum QShortcut &8D@>2K5 :;028H8Num Lock QShortcutNumLockNumLock QShortcut &8D@>2K5 :;028H8 Number Lock QShortcutB:@KBLOpen QShortcutB:@KBL URLOpen URL QShortcut ?F8OOption QShortcut!B@0=8F0 2=87 Page Down QShortcut!B@0=8F0 225@EPage Up QShortcutAB028BLPaste QShortcut PausePause QShortcut PgDownPgDown QShortcutPgUpPgUp QShortcut"5;5D>=Phone QShortcut7>1@065=8OPictures QShortcut>A?@>8725AB8Play QShortcutK:;NG8BL Power Down QShortcut$B:;NG5=85 ?8B0=8O Power Off QShortcut$@54K4CI89 20@80=BPrevious Candidate QShortcut PrintPrint QShortcut5G0BL M:@0=0 Print Screen QShortcut@8=B5@Printer QShortcut@0A=0ORed QShortcut$>2B>@8BL 459AB285Redo QShortcut1=>28BLRefresh QShortcut5@5703@C78BLReload QShortcutB25B8BLReply QShortcut ReturnReturn QShortcut ?@02>Right QShortcut>25@=CBL >:=0Rotate Windows QShortcut!>E@0=8BLSave QShortcut %@0=8B5;L M:@0=0 Screensaver QShortcut$$8:A0F8O ?@>:@CB:8 Scroll Lock QShortcutScrollLock ScrollLock QShortcut >8A:Search QShortcutK1@0BLSelect QShortcutB?@028BLSend QShortcut0AB@>9:8Settings QShortcut ShiftShift QShortcut03078=Shop QShortcut!?OI89 @568<Sleep QShortcut @>15;Space QShortcut&@>25@:0 >@D>3@0D88 Spellchecker QShortcut 0745;8BL M:@0= Split Screen QShortcut&-;5:B@>==0O B01;8FK Spreadsheet QShortcut 568< >6840=8OStandby QShortcutAB0=>28BLStop QShortcut!C1B8B@KSubtitle QShortcut>445@6:0Support QShortcut@8>AB0=>28BLSuspend QShortcut SysReqSysReq QShortcut !8AB5<=K9 70?@>ASystem Request QShortcutTabTab QShortcut0=5;L 7040G Task Panel QShortcut"5@<8=0;Terminal QShortcut @5<OTime QShortcut*!=OBL/?>;>68BL B@C1:CToggle Call/Hangup QShortcutP@8>AB0=>28BL/?@>4>;68BL 2>A?@>872545=85Toggle Media Play/Pause QShortcut=AB@C<5=BKTools QShortcut;02=>5 <5=NTop Menu QShortcutCB5H5AB285Travel QShortcut' =865 Treble Down QShortcut' 2KH5 Treble Up QShortcut2!25@EH8@>:>?>;>A=0O A2O7LUltra Wide Band QShortcut"B<5=8BL 459AB285Undo QShortcut 25@EUp QShortcut 845>Video QShortcut84View QShortcut>;>A>2>9 2K7>2 Voice Dial QShortcut"8H5 Volume Down QShortcutK:;NG8BL 72C: Volume Mute QShortcut @><G5 Volume Up QShortcutWWWWWW QShortcut@>1C645=85Wake Up QShortcutM1-:0<5@0WebCam QShortcut"5A?@>2>4=0O A5BLWireless QShortcut$"5:AB>2K9 @540:B>@Word Processor QShortcut Q;B0OYellow QShortcut0Yes QShortcut#25;8G8BLZoom QShortcut#25;8G8BLZoom In QShortcut#<5=LH8BLZoom Out QShortcut iTouchiTouch QShortcut8"8? 04@5A0 =5 ?>445@68205BAOAddress type not supportedQSocks5SocketEngineP!>548=5=85 =5 @07@5H5=> A5@25@>< SOCKSv5(Connection not allowed by SOCKSv5 serverQSocks5SocketEngine^!>548=5=85 A ?@>:A8-A5@25@>< =5>6840==> 70:@KB>&Connection to proxy closed prematurelyQSocks5SocketEngineN A>548=5=88 A ?@>:A8-A5@25@>< >B:070=>Connection to proxy refusedQSocks5SocketEngineZ@5<O =0 A>548=5=85 A ?@>:A8-A5@25@>< 8AB5:;>Connection to proxy timed outQSocks5SocketEngine,H81:0 A5@25@5 SOCKSv5General SOCKSv5 server failureQSocks5SocketEngineB@5<O =0 A5B52CN >?5@0F8N 8AB5:;>Network operation timed outQSocks5SocketEngineV5 C40;>AL 02B>@87>20BLAO =0 ?@>:A8-A5@25@5Proxy authentication failedQSocks5SocketEngine^5 C40;>AL 02B>@87>20BLAO =0 ?@>:A8-A5@25@5: %1Proxy authentication failed: %1QSocks5SocketEngine.@>:A8-A5@25@ =5 =0945=Proxy host not foundQSocks5SocketEngine0H81:0 ?@>B>:>;0 SOCKSv5SOCKS version 5 protocol errorQSocks5SocketEngineB><0=40 SOCKSv5 =5 ?>445@68205BAOSOCKSv5 command not supportedQSocks5SocketEngine!5BL =54>ABC?=0 TTL expiredQSocks5SocketEngineX58725AB=0O >H81:0 SOCKSv5 ?@>:A8 (:>4 0x%1)%Unknown SOCKSv5 proxy error code 0x%1QSocks5SocketEngine0480;>3 A ?@54C?@5645=85< alert messageQSpiAccessibleBridge0=8<0F8O animationQSpiAccessibleBridge?@8;>65=85 applicationQSpiAccessibleBridge?><>I=8: assistantQSpiAccessibleBridge<5=N :=>?:8 button menuQSpiAccessibleBridge0:=>?:0 A 2K?040NI8< <5=Nbutton with drop downQSpiAccessibleBridge8:=>?:0 A 2K?040NI59 B01;8F59button with drop down gridQSpiAccessibleBridge E>;ABcanvasQSpiAccessibleBridge OG59:0cellQSpiAccessibleBridge4803@0<<0chartQSpiAccessibleBridge D;06>: check boxQSpiAccessibleBridgeG0AKclockQSpiAccessibleBridge2K1>@ F25B0 color chooserQSpiAccessibleBridge:>;>=:0columnQSpiAccessibleBridge =0720=85 :>;>=:8 column headerQSpiAccessibleBridge"2K?040NI89 A?8A>: combo boxQSpiAccessibleBridge24>?>;=8B5;L=0O 8=D>@<0F8Ocomplementary contentQSpiAccessibleBridge:C@A>@ <KH8cursorQSpiAccessibleBridge@53C;OB>@dialQSpiAccessibleBridge 480;>3dialogQSpiAccessibleBridge4>:C<5=BdocumentQSpiAccessibleBridgeC@02=5=85equationQSpiAccessibleBridge70?>;=8B5;LfillerQSpiAccessibleBridge"=86=89 :>;>=B8BC;footerQSpiAccessibleBridge D>@<0formQSpiAccessibleBridge @0<:0frameQSpiAccessibleBridge3@0D8:0graphicQSpiAccessibleBridge"@53C;OB>@ @07<5@0gripQSpiAccessibleBridge703>;>2>:headingQSpiAccessibleBridge*2A?;K20NI0O ?>4A:07:0 help balloonQSpiAccessibleBridge<?>;5 4;O 22>40 3>@OG59 :;028H8 hotkey fieldQSpiAccessibleBridge8=48:0B>@ indicatorQSpiAccessibleBridge"=5:>@@5:B=0O @>;L invalid roleQSpiAccessibleBridge=04?8ALlabelQSpiAccessibleBridge :0A:04=0O ?0=5;L layered paneQSpiAccessibleBridge AAK;:0linkQSpiAccessibleBridge A?8A>:listQSpiAccessibleBridgeM;5<5=B A?8A:0 list itemQSpiAccessibleBridgeAB@>:0 <5=Nmenu barQSpiAccessibleBridgeM;5<5=B <5=N menu itemQSpiAccessibleBridge70<5B:0noteQSpiAccessibleBridge 2:;04:0 AB@0=8FKpage tabQSpiAccessibleBridgeA?8A>: 2:;04>: page tab listQSpiAccessibleBridge ?0=5;LpanelQSpiAccessibleBridge?0@03@0D paragraphQSpiAccessibleBridge 2A?;K20NI55 <5=N popup menuQSpiAccessibleBridge(8=48:0B>@ 2K?>;=5=8O progress barQSpiAccessibleBridge AB@0=8F0 A2>9AB2 property pageQSpiAccessibleBridge :=>?:0 push buttonQSpiAccessibleBridge?5@5:;NG0B5;L radio buttonQSpiAccessibleBridge AB@>:0rowQSpiAccessibleBridge=0720=85 AB@>:8 row headerQSpiAccessibleBridge ?>;>A0 ?@>:@CB:8 scroll barQSpiAccessibleBridge A5:F8OsectionQSpiAccessibleBridge@0745;8B5;L separatorQSpiAccessibleBridge?>;7C=>:sliderQSpiAccessibleBridge72C:soundQSpiAccessibleBridge?CAB>5 <5AB>spaceQSpiAccessibleBridgeG8A;>2>5 ?>;5spin boxQSpiAccessibleBridge @0745;8B5;L >:>=splitterQSpiAccessibleBridge AB@>:0 A>AB>O=8O status barQSpiAccessibleBridgeB01;8F0tableQSpiAccessibleBridge B5:ABtextQSpiAccessibleBridge:C@A>@ 2 B5:AB5 text caretQSpiAccessibleBridge AB@>:0 703>;>2:0 title barQSpiAccessibleBridge&?0=5;L 8=AB@C<5=B>2tool barQSpiAccessibleBridge?>4A:07:0tool tipQSpiAccessibleBridge 45@52>treeQSpiAccessibleBridgeM;5<5=B 45@520 tree itemQSpiAccessibleBridge=58725AB=0OunknownQSpiAccessibleBridgeweb-4>:C<5=B web documentQSpiAccessibleBridge`52>7<>6=> ?@54>AB028BL A5@B8D8:0B 157 :;NG0, %1,Cannot provide a certificate with no key, %1 QSslSocketFH81:0 A>740=8O :>=B5:AB0 SSL: (%1)Error creating SSL context (%1) QSslSocket<H81:0 A>740=8O A5AA88 SSL, %1Error creating SSL session, %1 QSslSocket<H81:0 A>740=8O A5AA88 SSL: %1Error creating SSL session: %1 QSslSocket6H81:0 :28B8@>20=8O SSL: %1Error during SSL handshake: %1 QSslSocketTH81:0 703@C7:8 ;>:0;L=>3> A5@B8D8:0B0, %1#Error loading local certificate, %1 QSslSocketFH81:0 703@C7:8 70:@KB>3> :;NG0, %1Error loading private key, %1 QSslSocket"H81:0 GB5=8O: %1Error while reading: %1 QSslSocketT5:>@@5:B=K9 8;8 ?CAB>9 A?8A>: H8D@>2 (%1)!Invalid or empty cipher list (%1) QSslSocket@5 C40;>AL ?@>25@8BL A5@B8D8:0BK!No certificates could be verified QSslSocket5B >H81:8No error QSslSocketh48= 87 A5@B8D8:0B>2 F5=B@0 A5@B8D8:0F88 =5:>@@5:B5=%One of the CA certificates is invalid QSslSocketd0:@KBK9 :;NG =5 A>>B25BAB2C5B >B:@KB><C :;NGC, %1+Private key does not certify public key, %1 QSslSocket>!>548=5=85 TLS/SSL 1K;> 70:@KB>&The TLS/SSL connection has been closed QSslSocket@52KH5=> 7=0G5=85 ?0@0<5B@0 4;8=K ?CB8 ?>;O basicConstraints A5@B8D8:0B0!@>: 459AB28O A5@B8D8:0B0 8ABQ:The certificate has expired QSslSocketR!@>: 459AB28O A5@B8D8:0B0 5IQ =5 =0ABC?8; The certificate is not yet valid QSslSocketf!5@B8D8:0B A0<>?>4?8A0==K9 8 =5 O2;O5BAO 7025@5==K<-The certificate is self-signed, and untrusted QSslSocketV5 C40;>AL @0AH8D@>20BL ?>4?8AL A5@B8D8:0B00The certificate signature could not be decrypted QSslSocketj>;5 notAfter A5@B8D8:0B0 A>45@68B =5:>@@5:B=>5 2@5<O9The certificate's notAfter field contains an invalid time QSslSocketl>;5 notBefore A5@B8D8:0B0 A>45@68B =5:>@@5:B=>5 2@5<O:The certificate's notBefore field contains an invalid time QSslSocket "5:CI89 A5@B8D8:0B 8740B5;O 1K; >B:;>=Q=, B0: :0: =0720=85 8740B5;O 8 A5@89=K9 =><5@ =5 A>2?040NB A 845=B8D8:0B>@>< :;NG0 A5@B8D8:0B0The current candidate issuer certificate was rejected because its issuer name and serial number was present and did not match the authority key identifier of the current certificate QSslSocket"5:CI89 A5@B8D8:0B 8740B5;O 1K; >B:;>=Q=, B0: :0: =0720=85 B5<K =5 A>2?0405B A =0720=85< 8740B5;O A5@B8D8:0B0The current candidate issuer certificate was rejected because its subject name did not match the issuer name of the current certificate QSslSocket0720=85 C7;0 =5 A>2?0405B A 4>?CAB8<K<8 =0720=8O<8 C7;>2 A5@B8D8:0B0GThe host name did not match any of the valid hosts for this certificate QSslSocketH5 C40;>AL =09B8 A5@B8D8:0B 8740B5;O)The issuer certificate could not be found QSslSocketv5 C40;>AL =09B8 A5@B8D8:0B 8740B5;O ;>:0;L=>3> A5@B8D8:0B0LThe issuer certificate of a locally looked up certificate could not be found QSslSocket>!5@B8D8:0B C7;0 2 GQ@=>< A?8A:5#The peer certificate is blacklisted QSslSocket<!5@B8D8:0B =5 1K; ?@54>AB02;5=(The peer did not present any certificate QSslSocket\5 C40;>AL ?@>G8B0BL >B:@KBK9 :;NG A5@B8D8:0B03The public key in the certificate could not be read QSslSocket>@=52>9 A5@B8D8:0B F5=B@0 A5@B8D8:0F88 >B<5G5= =0 >B:;>=5=85 4;O 40==>9 F5;8AThe root CA certificate is marked to reject the specified purpose QSslSocket>@=52>9 A5@B8D8:0B F5=B@0 A5@B8D8:0F88 =5 O2;O5BAO 7025@5==K< 4;O 40==>9 F5;87The root CA certificate is not trusted for this purpose QSslSocket>@=52>9 A5@B8D8:0B F5?>G:8 A5@B8D8:0B>2 A0<>?>4?8A0==K9 8 =5 O2;O5BAO 7025@5==K<KThe root certificate of the certificate chain is self-signed, and untrusted QSslSocket@5:>@@5:B=0O ?>4?8AL A5@B8D8:0B0+The signature of the certificate is invalid QSslSocketh@54AB02;5==K9 A5@B8D8:0B =5?@83>45= 4;O 40==>9 F5;87The supplied certificate is unsuitable for this purpose QSslSocketD5 C40;>AL @0AH8D@>20BL 40==K5: %1Unable to decrypt data: %1 QSslSocketX5 C40;>AL 8=8F80;878@>20BL :>=B5:AB SSL: %1Unable to init SSL Context: %1 QSslSocket<5 C40;>AL 70?8A0BL 40==K5: %1Unable to write data: %1 QSslSocket$58725AB=0O >H81:0 Unknown error QSslSocket4?@>B>:>; =5 ?>445@68205BAOunsupported protocol QSslSocket"0==K5 ?@8;>65=89Application DataQStandardPaths@8;>65=8O ApplicationsQStandardPathsMHCacheQStandardPaths0AB@>9:8 ConfigurationQStandardPaths 01>G89 AB>;DesktopQStandardPaths>:C<5=BK DocumentsQStandardPaths03@C7:8DownloadQStandardPaths (@8DBKFontsQStandardPaths ><0H=89 :0B0;>3HomeQStandardPaths $8;L<KMoviesQStandardPaths C7K:0MusicQStandardPaths7>1@065=8OPicturesQStandardPaths"A?>;=O5<K5 D09;KRuntimeQStandardPaths1I89 :MH Shared CacheQStandardPaths$1I0O :>=D83C@0F8OShared ConfigurationQStandardPaths1I85 40==K5 Shared DataQStandardPaths"@5<5==K9 :0B0;>3Temporary DirectoryQStandardPathsBACBAB2C5B A>AB>O=85 ?> C<>;G0=8N 2 8AB>@8G5A:>< A>AB>O=88 %1+Missing default state in history state '%1' QStateMachinerBACBAB2C5B 8AE>4=>5 A>AB>O=85 2 A>AB02=>< A>AB>O=88 %1,Missing initial state in compound state '%1' QStateMachine~5B >1I53> ?@54:0 C 8AB>G=8:0 8 F5;8 ?5@5E>40 87 A>AB>O=8O %1GNo common ancestor for targets and source of transition from state '%1' QStateMachine$58725AB=0O >H81:0 Unknown error QStateMachine$%1: C65 ACI5AB2C5B%1: already existsQSystemSemaphore"%1: =5 ACI5AB2C5B%1: does not existQSystemSemaphore2%1: =54>AB0B>G=> @5AC@A>2%1: out of resourcesQSystemSemaphore&%1: 4>ABC? 70?@5IQ=%1: permission deniedQSystemSemaphore2%1: =58725AB=0O >H81:0 %2%1: unknown error %2QSystemSemaphore:52>7<>6=> >B:@KBL A>548=5=85Unable to open connection QTDSDriverF52>7<>6=> 8A?>;L7>20BL 107C 40==KEUnable to use database QTDSDriver @>:@CB8BL 2;52> Scroll LeftQTabBar"@>:@CB8BL 2?@02> Scroll RightQTabBarH?5@0F8O A A>:5B>< =5 ?>445@68205BAO$Operation on socket is not supported QTcpServerT5 C40;>AL ?@>G8B0BL >:>=G0=85 87>1@065=8OCould not read footerQTgaFileN5 C40;>AL ?@>G8B0BL 40==K5 87>1@065=8OCould not read image dataQTgaFileB5 C40;>AL ?5@5<5AB8BLAO : 40==K<Could not reset to read dataQTgaFileX5 C40;>AL ?5@5<5AB8BLAO : :>=FC 87>1@065=8O#Could not seek to image read footerQTgaFileL54>?CAB8<0O 3;C18=0 F25B0 87>1@065=8OImage depth not validQTgaFileT5 C40;>AL ?@>G8B0BL 703>;>2>: 87>1@065=8OImage header read failedQTgaFilef5?>445@68205<K9 B8? 87>1@065=8O: =5 TrueVision 2.0-Image type (non-TrueVision 2.0) not supportedQTgaFile@5?>445@68205<K9 B8? 87>1@065=8OImage type not supportedQTgaFile5 C40;>AL ?@>8725AB8 ?5@5<5I5=85 ?> D09;C/CAB@>9AB2C 4;O GB5=8O 87>1@065=8O&Seek file/device for image read failedQTgaFile'B5=85 87 ?>A;54>20B5;L=KE CAB@>9AB2 (=0?@8<5@, 87 A>:5B0) =5 ?>445@68205BAO:Sequential device (eg socket) for image read not supportedQTgaFile$>2B>@8BL 459AB285Redo QUndoGroup>2B>@8BL %1Redo %1 QUndoGroup"B<5=8BL 459AB285Undo QUndoGroupB<5=8BL %1Undo %1 QUndoGroup<?CAB>> QUndoModel$>2B>@8BL 459AB285Redo QUndoStack>2B>@8BL %1Redo %1 QUndoStack"B<5=8BL 459AB285Undo QUndoStackB<5=8BL %1Undo %1 QUndoStack6FSI 5@20O 6QAB:0O 87>;OF8OFSI First strong isolateQUnicodeControlCharacterMenuFAB028BL C?@02;ONI89 A8<2>; Unicode Insert Unicode control characterQUnicodeControlCharacterMenu\LRE 0G0;> 2AB@0820=8O =0?8A0=8O A;520 =0?@02>$LRE Start of left-to-right embeddingQUnicodeControlCharacterMenuVLRI 0G0;> 87>;OF88 =0?8A0=8O A;520 =0?@02>LRI Left-to-right isolateQUnicodeControlCharacterMenuFLRM @87=0: =0?8A0=8O A;520 =0?@02>LRM Left-to-right markQUnicodeControlCharacterMenuRLRO 0G0;> 70<5=K =0?8A0=8O A;520 =0?@02>#LRO Start of left-to-right overrideQUnicodeControlCharacterMenujPDF @87=0: >:>=G0=8O =0?8A0=8O A 4@C38< =0?@02;5=85<PDF Pop directional formattingQUnicodeControlCharacterMenuNPDI >AAB0=>2;5=85 87>;OF88 =0?@02;5=8OPDI Pop directional isolateQUnicodeControlCharacterMenu\LRE 0G0;> 2AB@0820=8O =0?8A0=8O A?@020 =0;52>$RLE Start of right-to-left embeddingQUnicodeControlCharacterMenuVRLI 0G0;> 87>;OF88 =0?8A0=8O A?@020 =0;52>RLI Right-to-left isolateQUnicodeControlCharacterMenuFRLM @87=0: =0?8A0=8O A?@020 =0;52>RLM Right-to-left markQUnicodeControlCharacterMenuRRLO 0G0;> 70<5=K =0?8A0=8O A?@020 =0;52>#RLO Start of right-to-left overrideQUnicodeControlCharacterMenuLZWJ 1J548=ONI89 A8<2>; =C;52>9 H8@8=KZWJ Zero width joinerQUnicodeControlCharacterMenuRZWNJ 5>1J548=ONI89 A8<2>; =C;52>9 H8@8=KZWNJ Zero width non-joinerQUnicodeControlCharacterMenu4ZWSP @>15; =C;52>9 H8@8=KZWSP Zero width spaceQUnicodeControlCharacterMenu'B> MB>? What's This?QWhatsThisAction**QWidget&>?8@>20BL&CopyQWidgetTextControl&AB028BL&PasteQWidgetTextControl&&>2B>@8BL 459AB285&RedoQWidgetTextControl$&B<5=8BL 459AB285&UndoQWidgetTextControl2!:>?8@>20BL &04@5A AAK;:8Copy &Link LocationQWidgetTextControl&K@570BLCu&tQWidgetTextControl#40;8BLDeleteQWidgetTextControlK45;8BL 2AQ Select AllQWidgetTextControl\5 C40;>AL 703@C78BL <>4C;L ?;0BD>@<K direct2d$Cannot load direct2d platform pluginQWindowsDirect2DIntegrationQt =5 <>65B 703@C78BL <>4C;L ?;0BD>@<K direct2d, B0: :0: CAB0=>2;5==0O 25@A8O Direct2D A;8H:>< AB0@0O. 8=8<0;L=K5 B@51>20=8O MB>3> <>4C;O: Windows 7 SP1 A Platform Update. "@51C5BAO Direct2D 25@A88 =5 =865 %1.%2.%3.%4. 5@A8O >1=0@C65==>3> Direct2D: %5.%6.%7.%8.-Qt cannot load the direct2d platform plugin because the Direct2D version on this system is too old. The minimum system requirement for this platform plugin is Windows 7 SP1 with Platform Update. The minimum Direct2D version required is %1.%2.%3.%4. The Direct2D version on this system is %5.%6.%7.%8.QWindowsDirect2DIntegration&025@H8BL&FinishQWizard&!?@02:0&HelpQWizard &0;55&NextQWizard&0;55 >&Next >QWizard< &0704< &BackQWizard B<5=0CancelQWizard>4B25@48BLCommitQWizard@>4>;68BLContinueQWizard >B>2>DoneQWizard 0704Go BackQWizard!?@02:0HelpQWizardx2 >1JO2;5=88 XML B@51CNBAO ?0@0<5B@K encoding 8;8 standaloneYencoding declaration or standalone declaration expected while reading the XML declarationQXmlH>H81:0 2 >1JO2;5=88 2=5H=53> >1J5:B03error in the text declaration of an external entityQXml4>H81:0 @071>@0 :><<5=B0@8O$error occurred while parsing commentQXml0>H81:0 @071>@0 4>:C<5=B0$error occurred while parsing contentQXmlP>H81:0 @071>@0 >1JO2;5=8O B8?0 4>:C<5=B05error occurred while parsing document type definitionQXml.>H81:0 @071>@0 M;5<5=B0$error occurred while parsing elementQXml*>H81:0 @071>@0 AAK;:8&error occurred while parsing referenceQXml8>H81:0 2K720=0 ?>;L7>20B5;5<error triggered by consumerQXml`2=5H=OO AAK;:0 =0 >1I89 >1J5:B =54>?CAB8<0 2 DTD;external parsed general entity reference not allowed in DTDQXml|2=5H=OO AAK;:0 =0 >1I89 >1J5:B =54>?CAB8<0 2 7=0G5=88 0B@81CB0Gexternal parsed general entity reference not allowed in attribute valueQXmlf2=CB@5==OO AAK;:0 =0 >1I89 >1J5:B =54>?CAB8<0 2 DTD4internal general entity reference not allowed in DTDQXmlD=5:>@@5:B=>5 8<O 48@5:B82K @071>@0'invalid name for processing instructionQXmlB@51C5BAO 1C:20letter is expectedQXmlFC:070=> 1>;55 >4=>3> B8?0 4>:C<5=B0&more than one document type definitionQXml$>H81:8 >BACBAB2CNBno error occurredQXml&@5:C@A82=K5 >1J5:BKrecursive entitiesQXml\2 >1JO2;5=88 XML B@51C5BAO ?0@0<5B@ standaloneAstandalone declaration expected while reading the XML declarationQXml BM3 =5 A>2?0405B tag mismatchQXml$=5>6840==K9 A8<2>;unexpected characterQXml.=5>6840==K9 :>=5F D09;0unexpected end of fileQXmln=5@07>1@0==0O AAK;:0 =0 >1J5:B 2 =5?@028;L=>< :>=B5:AB5*unparsed entity reference in wrong contextQXmlV2 >1JO2;5=88 XML B@51C5BAO ?0@0<5B@ version2version expected while reading the XML declarationQXmlT=5:>@@5:B=>5 7=0G5=85 ?0@0<5B@0 standalone&wrong value for standalone declarationQXmlN%1  =5:>@@5:B=K9 845=B8D8:0B>@ PUBLIC.#%1 is an invalid PUBLIC identifier. QXmlStream`%1  =5 O2;O5BAO :>@@5:B=K< =0720=85< :>48@>2:8.%1 is an invalid encoding name. QXmlStream|%1 =5 O2;O5BAO :>@@5:B=K< =0720=85< >1@010BK205<>9 8=AB@C:F88.-%1 is an invalid processing instruction name. QXmlStream, ?>;CG8;8 ' , but got ' QXmlStream6B@81CB %1 ?5@5>?@545;Q=.Attribute '%1' redefined. QXmlStream<>48@>2:0 %1 =5 ?>445@68205BAOEncoding %1 is unsupported QXmlStreamb1=0@C65=> =5:>@@5:B=> 70:>48@>20==>5 A>45@68<>5.(Encountered incorrectly encoded content. QXmlStream01J5:B %1 =5 >1JO2;5=.Entity '%1' not declared. QXmlStream"@51C5BAO  Expected  QXmlStream8"@51CNBAO A8<2>;L=K5 40==K5.Expected character data. QXmlStream@8H=85 40==K5 2 :>=F5 4>:C<5=B0.!Extra content at end of document. QXmlStreamT5:>@@5:B=>5 >1JO2;5=85 ?@>AB@0=AB20 8<Q=.Illegal namespace declaration. QXmlStream05:>@@5:B=K9 A8<2>; XML.Invalid XML character. QXmlStream*5:>@@5:B=>5 8<O XML.Invalid XML name. QXmlStream>5:>@@5:B=0O AB@>:0 25@A88 XML.Invalid XML version string. QXmlStreamL5:>@@5:B=K9 0B@81CB 2 >1JO2;5=88 XML.%Invalid attribute in XML declaration. QXmlStream>5:>@@5:B=0O A8<2>;L=0O AAK;:0.Invalid character reference. QXmlStream,5:>@@5:B=K9 4>:C<5=B.Invalid document. QXmlStream<5:>@@5:B=>5 7=0G5=85 >1J5:B0.Invalid entity value. QXmlStream`5:>@@5:B=>5 =0720=85 >1@010BK205<>9 8=AB@C:F88.$Invalid processing instruction name. QXmlStream:NDATA 2 >1JO2;5=88 ?0@0<5B@0.&NDATA in parameter entity declaration. QXmlStreamT@5D8:A ?@>AB@0=AB20 8<Q= %1 =5 >1JO2;5="Namespace prefix '%1' not declared QXmlStreamVB:@K20NI89 BM3 =5 A>2?0405B A 70:@K20NI8<. Opening and ending tag mismatch. QXmlStream85>6840==K9 :>=5F 4>:C<5=B0.Premature end of document. QXmlStream:1=0@C65= @5:C@A82=K9 >1J5:B.Recursive entity detected. QXmlStreamd!AK;:0 =0 2=5H=89 >1J5:B %1 2 7=0G5=88 0B@81CB0.5Reference to external entity '%1' in attribute value. QXmlStreamJ!AK;:0 =0 =5>1@01>B0==K9 >1J5:B %1."Reference to unparsed entity '%1'. QXmlStreamd>A;54>20B5;L=>ABL ]]> =54>?CAB8<0 2 A>45@68<><.&Sequence ']]>' not allowed in content. QXmlStreamA524>0B@81CB standalone <>65B ?@8=8<0BL B>;L:> 7=0G5=8O yes 8;8 no."Standalone accepts only yes or no. QXmlStream4"@51C5BAO >B:@K20NI89 BM3.Start tag expected. QXmlStreamA524>0B@81CB standalone 4>;65= =0E>48BLAO ?>A;5 C:070=8O :>48@>2:8.?The standalone pseudo attribute must appear after the encoding. QXmlStream5>6840==>5 ' Unexpected ' QXmlStreamx5>6840==K9 A8<2>; %1 2 ;8B5@0;5 >B:@KB>3> 845=B8D8:0B>@0./Unexpected character '%1' in public id literal. QXmlStream85?>445@68205<0O 25@A8O XML.Unsupported XML version. QXmlStream^1JO2;5=85 XML =0E>48BAO =5 2 =0G0;5 4>:C<5=B0.)XML declaration not at start of document. QXmlStream ) , TreeLine-3.2.1/translations/qt_zh.qm000066400000000000000000003450541506556630100174530ustar00rootroot000000000000000~ee6_eEį į y~N^oxQ73m.(4B(4B(5B(5C0*yX*ym *y*TM*0'*0+Fw+F+L +f+f;+z.++m++z.++XYYKxYz9YQYAZg~ZkZLp[;^c\\]41\]4\\at#gclG|^acVv5vT$fS24Lu5.76CG<IA[Iysɵn1xɵn`aɵndɵnrɵnɵnɵnɪɵn˧(UY B* 'tM>EiuaW,qf o>\H,]<p5]#Q%UT(ŎC*4.-ct6205vXw^{x=|{yMcNGINW2zd2{'K.7R#Ai 9P` d-ytf.iU^y#[IgBurd  ~v Yd "l)*-S/=N1$5~P< g?2?NM %NkyUUiW~cXc]P`2`jt5lglyzgl}oivty0vtyP1J]"#O?l),s94G)e6w66^S{KmORT=|1~.$wϓ ?EE o {1=8AARO\[y%LX:n~o2u#BmxQMwDMEOEVLwwTV^Y I FLCr !e%B4&%)*/eH5"1;}ByKEc.,F4OZf\c`vbEcփ߲f&g&4 jCCdmnk8qq_tuZu({>}kaK0~"O\ _Q{y BFun$Ȭ$G+57(uʁr^K K*֊/ nt,a;y/O-QAnJ7^j=4&Ha>. /`?;IxS-MR>)YMPYMV^Ph^#i&Zssc|s+w$PZxFR/^q28^_~NA2Hc$\SJPqTVVFfR; M H  ^A es_$%C#I&~I&1)2h)6*4L+a,?"t?>u5J?KNYM֫R|kV|J]_]cdIgA k7y^ {y5t [FA):[ΞUvJG%Nn:ص'ǥ+)6Řt0{yS/G;LxALr9\LsL@"Ͼl%-0{GC-p5C^Yƨ dƨ˾cdtҝz-iէ?QZ>(z9xߺ`hs8fq.m}^=!  $v.~b@~bEhoMh0!b)ўQ+uW+3ʌ,8/J/A1Z4~ 6 ? 2AD!_GOGbDLAUOrPѧNQXSnTxUfHUVUT_/ZZZ(ZV[]k*@s]62^n_pseiSiYwkQ)oN%'y;sm{Z}u}w }wI}w }<'fr"#B>|vCtt.9.r399PiU'aDD;Yot(2tVt~{0"-n|_ n+Fu_C[ʢ3Qʢ(ƴd3duddd0 59b"э+] NSjU.dBhjwdj 2W ?M bc'V|O+Z,D/22742a6S7DM:r?;6CU]mDqIN9|J0KK U|]V7N>\artwKl|(^ ||T}wZ}$}$}$ ϗ{ZçVN^fD\BL>XSNqK<Hf+W·д·ý2Ƕ׳ /XF,TUENHgxVvu %5DTeh{ e~Oi~i 9%Pwb-#%%r'|-.zb.' 5kE=Շ= ?o/?rYCtIGPNV%XXU ?Zh``NvDbD$bGifBfdUgAmhII i$x1 זz*2x|QR6dJwlU (.v5z8Jc.[1-DrXmO^^_e n$Kba†5niFCʴ5wʴ5!ʶy}^ ^AԄx۔#D#'Nm4d5F5!(F5yYp]q+>BII?As 3 }$v| qeU ڤ}h ڥ dO EtE E  Ac} AcB!  35 u b bb b`^ b`  gUp i3% la{= lfq uu6 xq"% |oS | J t tA .$ ~ ` )M1 F>,[ 9 (r ~  B ҉ >̷  Z{ d t nqi Nr] Y+Ԍ K  팤X l~= %' ޽ /1( =! qK N }# o9 7V ) */? .>q 5^ 7u ;k& =N B BnE4 J" J"J K2# Rۮ 5 Ty ` T^ Uj4n ] `` ` bpI bP c(B cE d e e@B e{ f1Q/ f* g5U gn3 k, rD" t>nG :.R f  f = 4a .M- W# s] s> AAT, 9x 9w  m, #-t 0N+a 5 A CUM E9> I L( L' L9 Mc\ R^ Sb Ve W% ]$2@ f)Y f)== f=5 io>w m`" w xR/" yr5' >RI  t H H< *( nD $> .@  i  c p n3  %X J J> #I t. k Ӈ M  N>j( ̺Nc & -DO& .l ۷ c>IQ rM k+ k U)Y  <! y 0   z+  R  Y IHZ %MZ Np / C xH\ r 8>  .- 7F >Tq >U$ >U >\ >f >l >m >P ?t| DT ; I-X P@  RVBg RV RV S. SGP S Y Yz [ c`e hۮG j7o: p. vt 3 . Bda  T1 Ts3 T& T $ e/ 3 H S )d% Tq L ;>y .1 .` .s . .y .   a> y! o e.@ hNpb >X ҂$5  %1 u z 8 |Ґ l h Xtd n 9 t6 a >7 :bZ. Uqwb  O.< ʜ,  ]4 #$ #=f %nqb (I$ (N0\ +>/& +k 0E 64] ;ɾc Fg K9S Ptym Pt T>R W H dBg fe fe, g iFC i@ iV jӮ kGn m9 n'd u uL v o@ v& v{G w΂ w w * w}ΰ w} w} V |[+;  P V % J] ^{ }k R= P  xN Up ɰeh F}, ' X< &* D Ah + t5x t5 C a2 > z x ) y "Rw @afT);oAgT)4*'*n/E(/E=Bi+I_ZxKOOpXRuwX4 [ [ a.a./gcnyG*GvɅy$~[>Gn4y&m'@4Sf^Ǘ 0:B&rncݖ[y^{r h >JG3#lDb%"#o$UE%45%4D-v0i)߀01c2wTL<T<(]D#~HJd[IKK#hL$.Wbbc5dc5 g3iCmhpTyC${~a6$Y5 K&&_{j]`CnS[!>T&G>>bN:I E"~Ldr)1r?kyLn~kBLPt2+r`^dvU7ibp<html>RcbR0Ve>Y <b>%1</b> <br/>[RRSN:Su(^vNQwg fvOQH~0</html>xSwitching to the audio playback device %1
      which just became available and has higher preference. AudioOutputl<html>Ve>Y <b>%1</b> lg ]O\0<br/>VnR0 <b>%2</b>0</html>^The audio playback device %1 does not work.
      Falling back to %2. AudioOutput`bY R0Y %1 Revert back to device '%1' AudioOutput Qsh{~u Close Tab CloseButton QsN %1About %1MAC_APPLICATION_MENU%1Hide %1MAC_APPLICATION_MENUQvN Hide OthersMAC_APPLICATION_MENU POY}n &Preferences...MAC_APPLICATION_MENU Q %1Quit %1MAC_APPLICATION_MENUg RServicesMAC_APPLICATION_MENUQhf>y:Show AllMAC_APPLICATION_MENU exsX AccessibilityPhonon:: CommunicationPhonon::n8bGamesPhonon::NPMusicPhonon::w NotificationsPhonon::ƘVideoPhonon::ffTJw wge `lg [Wx@v GStreamer cN0 b@g vTƘe/c]~ψQs0~Warning: You do not seem to have the base GStreamer plugins installed. All audio and video support has been disabledPhonon::Gstreamer::BackendvfTJw wge `lg [ gstreamer0.10-plugins-good S0 NNƘry`']~ψQs0Warning: You do not seem to have the package gstreamer0.10-plugins-good installed. Some video features have been disabled.Phonon::Gstreamer::Backend>:\NN*vxVh0`[YN xVhgede>N*Q[%0`A required codec is missing. You need to install the following codec(s) to play this content: %0Phonon::Gstreamer::MediaObjectN _YVe>0 hg`v Gstreamer [^vNxn` ]~[ libgstreamer-plugins-base0wCannot start playback. Check your Gstreamer installation and make sure you have libgstreamer-plugins-base installed.Phonon::Gstreamer::MediaObjectN xZOSn0Could not decode media source.Phonon::Gstreamer::MediaObjectN [OMZOSn0Could not locate media source.Phonon::Gstreamer::MediaObject&N bS_󘑋Y0N*YkcW(Ou(0:Could not open audio device. The device is already in use.Phonon::Gstreamer::MediaObjectN bS_ZOSn0Could not open media source.Phonon::Gstreamer::MediaObjecteeHvn|{W0Invalid source type.Phonon::Gstreamer::MediaObject0Ou(N*nWW0g]N:%0 gSN:%1%WUse this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1%Phonon::VolumeSlider %1% Volume: %1%Phonon::VolumeSlider%1 %2g*[NI%1, %2 not definedQ3AccelN fxnv%1lg YtAmbiguous %1 not handledQ3AccelR dDelete Q3DataTablePGFalse Q3DataTablecQeInsert Q3DataTablewTrue Q3DataTablefeUpdate Q3DataTable*eN%1 g*b~R00 hg_TeNT 0 +%1 File not found. Check path and filename. Q3FileDialog R d(&D)&Delete Q3FileDialog T&(&N)&No Q3FileDialog xn[(&O)&OK Q3FileDialog bS_(&O)&Open Q3FileDialogT}T (&R)&Rename Q3FileDialog O[X(&S)&Save Q3FileDialogg*cRv(&U) &Unsorted Q3FileDialog f/(&Y)&Yes Q3FileDialog0<qt>O`xnO``R d%1 %2 </qt>1Are you sure you wish to delete %1 "%2"? Q3FileDialogb@g eN (*) All Files (*) Q3FileDialogb@g eN (*.*)All Files (*.*) Q3FileDialog\^`' Attributes Q3FileDialogTBack Q3FileDialogSmCancel Q3FileDialogY R6byRNN*eNCopy or Move a File Q3FileDialog R^eeNY9Create New Folder Q3FileDialogegDate Q3FileDialogR d%1 Delete %1 Q3FileDialog~ƉV Detail View Q3FileDialogv_UDir Q3FileDialogv_U Directories Q3FileDialogv_U Directory: Q3FileDialogError Q3FileDialogeNFile Q3FileDialogeNT y(&N) File &name: Q3FileDialogeN|{W(&T) File &type: Q3FileDialoggb~v_UFind Directory Q3FileDialog N Sv Inaccessible Q3FileDialogRhV List View Q3FileDialoggb~V(&I) Look &in: Q3FileDialogT yName Q3FileDialog e^eNY9 New Folder Q3FileDialoge^eNY9%1 New Folder %1 Q3FileDialog e^eNY91 New Folder 1 Q3FileDialogTN N~One directory up Q3FileDialogbS_Open Q3FileDialogbS_Open  Q3FileDialog eNQ[Preview File Contents Q3FileDialog eNO`oPreview File Info Q3FileDialoge}Qe(&E)R&eload Q3FileDialogS Read-only Q3FileDialogQ Read-write Q3FileDialog S%1Read: %1 Q3FileDialogS[XN:Save As Q3FileDialog bNN*v_USelect a Directory Q3FileDialogf>y:eN(&H)Show &hidden files Q3FileDialogY'\Size Q3FileDialogcRSort Q3FileDialogc egcR(&D) Sort by &Date Q3FileDialogc T ycR(&N) Sort by &Name Q3FileDialogc Y'\cR(&S) Sort by &Size Q3FileDialogrykSpecial Q3FileDialogv_Uv|~ߔcSymlink to Directory Q3FileDialogeNv|~ߔcSymlink to File Q3FileDialogrykv|~ߔcSymlink to Special Q3FileDialog|{WType Q3FileDialogSQ Write-only Q3FileDialog QQe%1 Write: %1 Q3FileDialogv_U the directory Q3FileDialogeNthe file Q3FileDialog|~ߔc the symlink Q3FileDialogN R^v_U %1Could not create directory %1 Q3LocalFsN bS_ %1Could not open %1 Q3LocalFsN Sv_U %1Could not read directory %1 Q3LocalFsN ydeNbv_U %1%Could not remove file or directory %1 Q3LocalFsN b %1 T}T N: %2Could not rename %1 to %2 Q3LocalFsN QQe %1Could not write %1 Q3LocalFs [NI... Customize... Q3MainWindowcRLine up Q3MainWindowdO\u(b7P\kbOperation stopped by the userQ3NetworkProtocolSmCancelQ3ProgressDialog^u(Apply Q3TabDialogSmCancel Q3TabDialog؋Defaults Q3TabDialog^.RHelp Q3TabDialogxnOK Q3TabDialog Y R6(&C)&Copy Q3TextEdit |4(&P)&Paste Q3TextEdit `bY (&R)&Redo Q3TextEdit dm(&U)&Undo Q3TextEditnzzClear Q3TextEdit RjR(&T)Cu&t Q3TextEdit bQh Select All Q3TextEditQsClose Q3TitleBarQszSCloses the window Q3TitleBarST+dO\zSvT}N0*Contains commands to manipulate the window Q3TitleBar f>y:zST y^vNST+~b[vcNFDisplays the name of the window and contains controls to manipulate it Q3TitleBar zSQh\OSMakes the window full screen Q3TitleBargY'SMaximize Q3TitleBarg\SMinimize Q3TitleBarbzSyR0YbMoves the window out of the way Q3TitleBarbNN*gY'SzS`bY N:fnr`&Puts a maximized window back to normal Q3TitleBarbNN*g\SzS`bY N:fnr`Puts a minimized back to normal Q3TitleBarTN `bY  Restore down Q3TitleBarTN `bY  Restore up Q3TitleBar|~System Q3TitleBar fY...More... Q3ToolBar (g*wv) (unknown) Q3UrlOperator*SO %1 N e/cY R6byReNbv_UIThe protocol `%1' does not support copying or moving files or directories Q3UrlOperatorSO %1 N e/cR^ev_U;The protocol `%1' does not support creating new directories Q3UrlOperatorSO %1 N e/cSeN0The protocol `%1' does not support getting files Q3UrlOperatorSO %1 N e/cRQv_U6The protocol `%1' does not support listing directories Q3UrlOperatorSO %1 N e/cN O eN0The protocol `%1' does not support putting files Q3UrlOperator"SO %1 N e/cydeNbv_U@The protocol `%1' does not support removing files or directories Q3UrlOperator$SO %1 N e/cT}T eNbv_U@The protocol `%1' does not support renaming files or directories Q3UrlOperatorSO %1 N e/c"The protocol `%1' is not supported Q3UrlOperator Sm(&C)&CancelQ3Wizard [b(&F)&FinishQ3Wizard ^.R(&H)&HelpQ3WizardN Nke(&N) >&Next >Q3Wizard< N Nke(&B)< &BackQ3Wizard cb~Connection refusedQAbstractSocketceConnection timed outQAbstractSocket N;g:g*b~R0Host not foundQAbstractSocket Q~N Network unreachableQAbstractSocketSocketdO\N e/c$Operation on socket is not supportedQAbstractSocketYWc[Wlg cSocket is not connectedQAbstractSocketYWc[WdO\eSocket operation timed outQAbstractSocket bQh(&S) &Select AllQAbstractSpinBox XR(&S)&Step upQAbstractSpinBox Q\(&D) Step &downQAbstractSpinBoxom;Activate QApplicationom;N*z ^vN;zS#Activates the program's main window QApplication0bgL %1 Qt %2 Sb~R0NQt %30,Executable '%1' requires Qt %2, found Qt %3. QApplicationN Q|[vQtIncompatible Qt Library Error QApplication Sm(&C)&Cancel QAxSelectCOM[a(&O) COM &Object: QAxSelectxn[OK QAxSelect bActiveXcNSelect ActiveX Control QAxSelect N-Check QCheckBoxRcbToggle QCheckBoxSm N-Uncheck QCheckBoxmRR0[NIr(&A)&Add to Custom Colors QColorDialogWg,r(&B) &Basic colors QColorDialog[NIr(&C)&Custom colors QColorDialog~r(&G)&Green: QColorDialog~r(&R)&Red: QColorDialogqT^(&S)&Sat: QColorDialogN^(&V)&Val: QColorDialogAlphaS(&A)A&lpha channel: QColorDialog݂r(&U)Bl&ue: QColorDialogr(&E)Hu&e: QColorDialog b阜r Select Color QColorDialogQsClose QComboBoxPGFalse QComboBoxbS_Open QComboBoxwTrue QComboBox%1ftok Y1%%1: ftok failedQCoreApplication%1.f/zzv%1: key is emptyQCoreApplication%1N R6 .%1: unable to make keyQCoreApplication N cNNRUnable to commit transaction QDB2DriverN cUnable to connect QDB2Driver N VnNRUnable to rollback transaction QDB2DriverN nRcNUnable to set autocommit QDB2Driver N ^.[SؑUnable to bind variable QDB2Result N bgLSUnable to execute statement QDB2ResultN S{,NN*Unable to fetch first QDB2ResultN SN NN*Unable to fetch next QDB2ResultN S֋_U%1Unable to fetch record %1 QDB2Result N QYSUnable to prepare statement QDB2ResultAMAM QDateTimeEditPMPM QDateTimeEditamam QDateTimeEditpmpm QDateTimeEdit QDialQDialQDialSliderHandle SliderHandleQDialSpeedoMeter SpeedoMeterQDial[bDoneQDialog f/NNH What's This?QDialog egOe9 Date Modified QDirModel|{WKind QDirModelT yName QDirModelY'\Size QDirModel|{WType QDirModelQsClose QDockWidgetcDock QDockWidgetmnRFloat QDockWidgetf\LessQDoubleSpinBoxfYMoreQDoubleSpinBox xn[(&O)&OK QErrorMessageQk!f>y:N*m`o(&S)&Show this message again QErrorMessage m`oDebug Message: QErrorMessage T} Fatal Error: QErrorMessagefTJWarning: QErrorMessageelR^ %1 Cannot create %1 for outputQFileelՏQe %1 Cannot open %1 for inputQFileelՏQCannot open for outputQFilevheN][XW(Destination file existsQFileQWWY1%Failure to write blockQFile.v_U%1 lg b~R00 h8[]~[kcxnv_UT 0K%1 Directory not found. Please verify the correct directory name was given. QFileDialog.eN%1 lg b~R00 h8[]~[kcxneNT 0A%1 File not found. Please verify the correct file name was given. QFileDialog %1]~[XW(0 O``fcb[NH-%1 already exists. Do you want to replace it? QFileDialog b(&C)&Choose QFileDialog R d(&D)&Delete QFileDialoge^eNY9(&N) &New Folder QFileDialog bS_(&O)&Open QFileDialogT}T (&R)&Rename QFileDialog O[X(&S)&Save QFileDialog( %1 f/QObv0 O`f/`R d[NH9'%1' is write protected. Do you want to delete it anyway? QFileDialogb@g eN (*) All Files (*) QFileDialogb@g eN (*.*)All Files (*.*) QFileDialogO`xnO``R d %1 !Are sure you want to delete '%1'? QFileDialogTBack QFileDialogN R dv_U0Could not delete directory. QFileDialog R^eeNY9Create New Folder QFileDialog~ƉV Detail View QFileDialogv_U Directories QFileDialogv_U Directory: QFileDialogqRVhDrive QFileDialogeNFile QFileDialogeNT y(&N) File &name: QFileDialog eN|{WFiles of type: QFileDialoggb~v_UFind Directory QFileDialogRMForward QFileDialogRhV List View QFileDialoggw Look in: QFileDialog bv{g: My Computer QFileDialog e^eNY9 New Folder QFileDialogbS_Open QFileDialogr6v_UParent Directory QFileDialog gvW0e Recent Places QFileDialogydRemove QFileDialogS[XN:Save As QFileDialogf>y: Show  QFileDialogf>y:eN(&H)Show &hidden files QFileDialogg*wvUnknown QFileDialog %1 GB%1 GBQFileSystemModel %1SC[W%1 KBQFileSystemModel %1 MB%1 MBQFileSystemModel %1 TB%1 TBQFileSystemModel%1[W%1 bytesQFileSystemModel`<b>T y %1 N Ou(0</b><p>Ou(SYNN*ST+f\[W{&bN T+g hp{&SvT y0oThe name "%1" can not be used.

      Try using another name, with fewer characters or no punctuations marks.QFileSystemModel{g:ComputerQFileSystemModel egOe9 Date ModifiedQFileSystemModel eeHeNT Invalid filenameQFileSystemModel|{WKindQFileSystemModel bv{g: My ComputerQFileSystemModelT yNameQFileSystemModelY'\SizeQFileSystemModel|{WTypeQFileSystemModelNaAny QFontDatabase?bO/eArabic QFontDatabase N\_NRequest abortedQHttpSSL cbKY1%SSL handshake failedQHttpg RVh_^8W0QsNc%Server closed connection unexpectedlyQHttp g*wv Unknown errorQHttpb@c[vSOf/g*wvUnknown protocol specifiedQHttpvQ[^Wrong content lengthQHttpAuthentication requiredQHttpSocketEngineg*e6R0NtvHTTPT^(Did not receive HTTP response from proxyQHttpSocketEngineTHTTPNteSu#Error communicating with HTTP proxyQHttpSocketEnginegNtvlBQ/Error parsing authentication request from proxyQHttpSocketEngineNtceQs#Proxy connection closed prematurelyQHttpSocketEngineNtcb~Proxy connection refusedQHttpSocketEngine Ntb~ݏcProxy denied connectionQHttpSocketEngineNtg RVhce!Proxy server connection timed outQHttpSocketEngineg*b~R0Ntg RVhProxy server not foundQHttpSocketEngine N _YNRCould not start transaction QIBaseDriverbS_epcn^Error opening database QIBaseDriver N cNNRUnable to commit transaction QIBaseDriver N VnNRUnable to rollback transaction QIBaseDriver N RMSCould not allocate statement QIBaseResultN cϏQeS"Could not describe input statement QIBaseResult N cϏSCould not describe statement QIBaseResultN SN NyCould not fetch next item QIBaseResult N b~R0ep~Could not find array QIBaseResultN _R0ep~epcnCould not get array data QIBaseResultN _R0gO`oCould not get query info QIBaseResultN _R0SO`oCould not get statement info QIBaseResult N QYSCould not prepare statement QIBaseResult N _YNRCould not start transaction QIBaseResult N QsSUnable to close statement QIBaseResult N cNNRUnable to commit transaction QIBaseResultN R^BLOBUnable to create BLOB QIBaseResult N bgLgUnable to execute query QIBaseResultN bS_BLOBUnable to open BLOB QIBaseResultN SBLOBUnable to read BLOB QIBaseResultN QQeBLOBUnable to write BLOB QIBaseResultYN lg zzNNo space left on device QIODevicelg N*eNbv_UNo such file or directory QIODevice gCPb~Permission denied QIODeviceY*YbS_veNToo many open files QIODevice g*wv Unknown error QIODeviceMac OS XQelMac OS X input method QInputContextWindowsQelWindows input method QInputContextXIMXIM QInputContext XIMQelXIM input method QInputContext QeNN*P<Enter a value: QInputDialogelR}^%1%2Cannot load library %1: %2QLibrary"elՉg%2N-v{&S %1 %3$Cannot resolve symbol "%1" in %2: %3QLibraryelSx}^%1%2Cannot unload library %1: %2QLibraryN f \ %1 %2Could not mmap '%1': %2QLibraryN Smf \ %1 %2Could not unmap '%1': %2QLibrary %1 N-vcNepcnN S9M)Plugin verification data mismatch in '%1'QLibrary eN %1 N f/g eHvQtcN0'The file '%1' is not a valid Qt plugin.QLibrary@cN %1 Ou(NN Q|[vQt^0(%2.%3.%4) [%5]=The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5]QLibraryJcN %1 Ou(NN Q|[vQt^0(N mTOu(^vrHg,TS^rHg,0)WThe plugin '%1' uses incompatible Qt library. (Cannot mix debug and release libraries.)QLibraryLcN %1 Ou(NN Q|[vQt^0g_vg^.f/ %2  _R0vStf/ %3 OThe plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3"QLibraryQqN^lg b~R00!The shared library was not found.QLibrary g*wv Unknown errorQLibrary Y R6(&C)&Copy QLineEdit |4(&P)&Paste QLineEdit `bY (&R)&Redo QLineEdit dm(&U)&Undo QLineEdit RjR(&T)Cu&t QLineEditR dDelete QLineEdit bQh Select All QLineEdit%1W0W@kcW(Ou(%1: Address in use QLocalServer%1: T y%1: Name error QLocalServer%1gCPb~%1: Permission denied QLocalServer%1g*w %2%1: Unknown error %2 QLocalServer%1c%1: Connection error QLocalSocket%1cb~%1: Connection refused QLocalSocket%1epcnbY*Y'%1: Datagram too large QLocalSocket%1eeHT y%1: Invalid name QLocalSocket%1z ]Qs%1: Remote closed QLocalSocket%1YWc[W%1: Socket access error QLocalSocket%1YWc[WdO\e%1: Socket operation timed out QLocalSocket%1YWc[WDn%1: Socket resource error QLocalSocket%1YWc[WdO\N e/c)%1: The socket operation is not supported QLocalSocket%1g*w%1: Unknown error QLocalSocket%1g*w %2%1: Unknown error %2 QLocalSocket N _YNRUnable to begin transaction QMYSQLDriver N cNNRUnable to commit transaction QMYSQLDriverN cUnable to connect QMYSQLDriverN bS_epcn^Unable to open database ' QMYSQLDriver N VnNRUnable to rollback transaction QMYSQLDriver N ~[YP<Unable to bind outvalues QMYSQLResult N ~[P<Unable to bind value QMYSQLResultN bgLN NN*gUnable to execute next query QMYSQLResult N bgLgUnable to execute query QMYSQLResult N bgLSUnable to execute statement QMYSQLResult N SepcnUnable to fetch data QMYSQLResult N QYSUnable to prepare statement QMYSQLResult N nSUnable to reset statement QMYSQLResultN [XPN NN*~gUnable to store next result QMYSQLResult N [XP~gUnable to store result QMYSQLResultN [XPS~g!Unable to store statement results QMYSQLResult (g*T}T v) (Untitled)QMdiArea%1 - [%2] %1 - [%2] QMdiSubWindow Qs(&C)&Close QMdiSubWindow yR(&M)&Move QMdiSubWindow `bY (&R)&Restore QMdiSubWindow Y'\(&S)&Size QMdiSubWindow - [%1]- [%1] QMdiSubWindowQsClose QMdiSubWindow^.RHelp QMdiSubWindowgY'S(&X) Ma&ximize QMdiSubWindowgY'SMaximize QMdiSubWindowSUMenu QMdiSubWindowg\S(&N) Mi&nimize QMdiSubWindowg\SMinimize QMdiSubWindow`bY Restore QMdiSubWindowTN `bY  Restore Down QMdiSubWindown=Shade QMdiSubWindow`;W(gRM(&T) Stay on &Top QMdiSubWindowSmn=Unshade QMdiSubWindowQsCloseQMenubgLExecuteQMenubS_OpenQMenuQsNQtAbout Qt QMessageBox^.RHelp QMessageBox ~Ƃ & &Hide Details... QMessageBoxxn[OK QMessageBox f>y:~Ƃ & &Show Details... QMessageBox b鏓Qel Select IMQMultiInputContextYQelRcbVhMultiple input method switcherQMultiInputContextPlugin*Ou(eg,zSNN N eSUvYQelRcbVhMMultiple input method switcher that uses the context menu of the text widgetsQMultiInputContextPlugin SNN*YWc[W]~kcW(vT,T NzS4Another socket is already listening on the same portQNativeSocketEngine2VW(N e/cIPv6e/cv^sSN Ou(IPv6YWc[W=Attempt to use IPv6 socket on a platform with no IPv6 supportQNativeSocketEngine cb~Connection refusedQNativeSocketEngineceConnection timed outQNativeSocketEngineN SѐY'vepcnbDatagram was too large to sendQNativeSocketEngine N;g:N Host unreachableQNativeSocketEngineeeHvYWc[WcϏ{&Invalid socket descriptorQNativeSocketEngineQ~ܕ Network errorQNativeSocketEngine Q~dO\eNetwork operation timed outQNativeSocketEngine Q~N Network unreachableQNativeSocketEngine[^YWc[WdO\Operation on non-socketQNativeSocketEngine Dn\=NOut of resourcesQNativeSocketEngine gCPb~Permission deniedQNativeSocketEngineSO|{WN e/cProtocol type not supportedQNativeSocketEngineN*W0W@N Su(The address is not availableQNativeSocketEngineN*W0W@ObNThe address is protectedQNativeSocketEngineT/u(vW0W@]~ψOu(#The bound address is already in useQNativeSocketEngine[NN*dO\Nt|{Wf/eeHv0,The proxy type is invalid for this operationQNativeSocketEnginezN;g:QsNN*c%The remote host closed the connectionQNativeSocketEngineN RYS^dYWc[W%Unable to initialize broadcast socketQNativeSocketEngineN RYS^;X^YWc[W(Unable to initialize non-blocking socketQNativeSocketEngineN ce6NN*m`oUnable to receive a messageQNativeSocketEngineN SѐNN*m`oUnable to send a messageQNativeSocketEngineN QQeUnable to writeQNativeSocketEngine g*wv Unknown errorQNativeSocketEngineN e/cvYWc[WdO\Unsupported socket operationQNativeSocketEnginebS_%1SuError opening %1QNetworkAccessCacheBackendelbS_ %1_f/NN*v_U#Cannot open %1: Path is a directoryQNetworkAccessFileBackendbS_ %1 %2Error opening %1: %2QNetworkAccessFileBackendS %1 %2Read error reading from %1: %2QNetworkAccessFileBackend kcW(bS_^g,W0eN %1 vlB%Request for opening non-local file %1QNetworkAccessFileBackendQQe %1 %2Write error writing to %1: %2QNetworkAccessFileBackendelՋS %1f/NN*v_UCannot open %1: is a directoryQNetworkAccessFtpBackendN } %1 e%2Error while downloading %1: %2QNetworkAccessFtpBackendN } %1 e%2Error while uploading %1: %2QNetworkAccessFtpBackendv{Qe %1 Y1%0Logging in to %1 failed: authentication requiredQNetworkAccessFtpBackendg*b~R0TvNtNo suitable proxy foundQNetworkAccessFtpBackendg*b~R0TvNtNo suitable proxy foundQNetworkAccessHttpBackend&N } %1  - g RVhVY %2)Error downloading %1 - server replied: %2 QNetworkReplySO %1 f/g*wvProtocol "%1" is unknown QNetworkReply dO\SmOperation canceledQNetworkReplyImpl N _YNRUnable to begin transaction QOCIDriver N cNNRUnable to commit transaction QOCIDriver N RYSUnable to initialize QOCIDriverN v{_UUnable to logon QOCIDriver N VnNRUnable to rollback transaction QOCIDriver N RMSUnable to alloc statement QOCIResultN ~[byYtbgLvR'Unable to bind column for batch execute QOCIResult N ~[P<Unable to bind value QOCIResultN bgLbyYtS!Unable to execute batch statement QOCIResult N bgLSUnable to execute statement QOCIResultN QeN NN*Unable to goto next QOCIResult N QYSUnable to prepare statement QOCIResult N cNNRUnable to commit transaction QODBCDriverN cUnable to connect QODBCDriver N c qRz ^N e/cb@g RCUnable to connect - Driver doesn't support all needed functionality QODBCDriverN ykbRcNUnable to disable autocommit QODBCDriverN bS_RcNUnable to enable autocommit QODBCDriver N VnNRUnable to rollback transaction QODBCDriverQODBCResult::reset: N b SQL_CURSOR_STATIC nN:S\^`'0hgO`vODBCqRz ^n0yQODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration QODBCResult N ^.[SؑUnable to bind variable QODBCResult N bgLSUnable to execute statement QODBCResultN SUnable to fetch QODBCResultN S{,NN*Unable to fetch first QODBCResultN SgTNN*Unable to fetch last QODBCResultN SN NN*Unable to fetch next QODBCResultN SN NN*Unable to fetch previous QODBCResult N QYSUnable to prepare statement QODBCResult[HomeQObjecteeHv URI%1Invalid URI: %1QObject g*c[N;g:T No host name givenQObjectW( %1 N N e/cvdO\Operation not supported on %1QObject SOe6R0NY'\N: 0 vS)Protocol error: packet of size 0 receivedQObjectS %1 %2Read error reading from %1: %2QObject*z N;g:eW0QsNW( %1 N vN*c3Remote host closed the connection prematurely on %1QObject%1 N vYWc[W%2Socket error on %1: %2QObjectQQe %1 %2Write error writing to %1: %2QObjectT yNameQPPDOptionsModelP<ValueQPPDOptionsModel N _YNRCould not begin transaction QPSQLDriver N cNNRCould not commit transaction QPSQLDriver N VnNRCould not rollback transaction QPSQLDriverN cUnable to connect QPSQLDriverN Unable to subscribe QPSQLDriver N SmUnable to unsubscribe QPSQLDriver N R^gUnable to create query QPSQLResult N QYSUnable to prepare statement QPSQLResultS|s (cm)Centimeters (cm)QPageSetupWidgetzOSFormQPageSetupWidget^Height:QPageSetupWidget[ (in) Inches (in)QPageSetupWidgetj*T LandscapeQPageSetupWidgetMarginsQPageSetupWidgetk|s (mm)Millimeters (mm)QPageSetupWidgeteT OrientationQPageSetupWidget ~_ Y'\ Page size:QPageSetupWidget~_ PaperQPageSetupWidget~_ n Paper source:QPageSetupWidget p (pt) Points (pt)QPageSetupWidget~TPortraitQPageSetupWidgetSTj*TReverse landscapeQPageSetupWidgetST~TReverse portraitQPageSetupWidget[^Width:QPageSetupWidgetN  bottom marginQPageSetupWidget]揹 left marginQPageSetupWidgetS󏹍 right marginQPageSetupWidgetN  top marginQPageSetupWidget Sm(&C)&CancelQPlatformTheme Qs(&C)&CloseQPlatformTheme T&(&N)&NoQPlatformTheme xn[(&O)&OKQPlatformTheme O[X(&S)&SaveQPlatformTheme f/(&Y)&YesQPlatformThemee>_AbortQPlatformTheme^u(ApplyQPlatformThemeSmCancelQPlatformThemeQsCloseQPlatformTheme N O[XQsClose without SavingQPlatformThemeb_DiscardQPlatformThemeN O[X Don't SaveQPlatformTheme^.RHelpQPlatformTheme_ueIgnoreQPlatformThemeQhT&(&O) N&o to AllQPlatformThemexn[OKQPlatformThemebS_OpenQPlatformThemenResetQPlatformTheme`bY ؋Restore DefaultsQPlatformTheme͋RetryQPlatformThemeO[XSaveQPlatformThemeO[XQhSave AllQPlatformThemeQhf/(&A) Yes to &AllQPlatformThemecNlg }Qe0The plugin was not loaded. QPluginLoader g*wv Unknown error QPluginLoader%1]~[XW(0 O``v[NH/%1 already exists. Do you want to overwrite it? QPrintDialog&%1f/v_U0 bNN*N T veNT 07%1 is a directory. Please choose a different file name. QPrintDialog y(&O) << &Options << QPrintDialog y(&O) >> &Options >> QPrintDialog bSSp(&P)&Print QPrintDialog <qt>O``v[NH</qt>%Do you want to overwrite it? QPrintDialogA0A0 QPrintDialog$A0 (841 x 1189 k|s)A0 (841 x 1189 mm) QPrintDialogA1A1 QPrintDialog"A1 (594 x 841 k|s)A1 (594 x 841 mm) QPrintDialogA2A2 QPrintDialog"A2 (420 x 594 k|s)A2 (420 x 594 mm) QPrintDialogA3A3 QPrintDialog"A3 (297 x 420 k|s)A3 (297 x 420 mm) QPrintDialogA4A4 QPrintDialog@A4 (210 x 297 k|s 8.26 x 11.7 [)%A4 (210 x 297 mm, 8.26 x 11.7 inches) QPrintDialogA5A5 QPrintDialog"A5 (148 x 210 k|s)A5 (148 x 210 mm) QPrintDialogA6A6 QPrintDialog"A6 (105 x 148 k|s)A6 (105 x 148 mm) QPrintDialogA7A7 QPrintDialog A7 (74 x 105 k|s)A7 (74 x 105 mm) QPrintDialogA8A8 QPrintDialogA8 (52 x 74 k|s)A8 (52 x 74 mm) QPrintDialogA9A9 QPrintDialogA9 (37 x 52 k|s)A9 (37 x 52 mm) QPrintDialog R+T %1 Aliases: %1 QPrintDialogB0B0 QPrintDialog&B0 (1000 x 1414 k|s)B0 (1000 x 1414 mm) QPrintDialogB1B1 QPrintDialog$B1 (707 x 1000 k|s)B1 (707 x 1000 mm) QPrintDialogB10B10 QPrintDialog B10 (31 x 44 k|s)B10 (31 x 44 mm) QPrintDialogB2B2 QPrintDialog"B2 (500 x 707 k|s)B2 (500 x 707 mm) QPrintDialogB3B3 QPrintDialog"B3 (353 x 500 k|s)B3 (353 x 500 mm) QPrintDialogB4B4 QPrintDialog"B4 (250 x 353 k|s)B4 (250 x 353 mm) QPrintDialogB5B5 QPrintDialog@B5 (176 x 250 k|s 6.93 x 9.84 [)%B5 (176 x 250 mm, 6.93 x 9.84 inches) QPrintDialogB6B6 QPrintDialog"B6 (125 x 176 k|s)B6 (125 x 176 mm) QPrintDialogB7B7 QPrintDialog B7 (88 x 125 k|s)B7 (88 x 125 mm) QPrintDialogB8B8 QPrintDialogB8 (62 x 88 k|s)B8 (62 x 88 mm) QPrintDialogB9B9 QPrintDialogB9 (44 x 62 k|s)B9 (44 x 62 mm) QPrintDialogC5EC5E QPrintDialog$C5E (163 x 229 k|s)C5E (163 x 229 mm) QPrintDialog[NICustom QPrintDialogDLEDLE QPrintDialog$DLE (110 x 220 k|s)DLE (110 x 220 mm) QPrintDialogQ{VeNf Executive QPrintDialogHExecutive (7.5 x 10 [ 191 x 254 k|s))Executive (7.5 x 10 inches, 191 x 254 mm) QPrintDialog*eN%1N SQ0 bNN*N T veNT 0=File %1 is not writable. Please choose a different file name. QPrintDialogeN[XW( File exists QPrintDialog[_~Folio QPrintDialog(Folio (210 x 330 k|s)Folio (210 x 330 mm) QPrintDialog^uLedger QPrintDialog*Ledger (432 x 279 k|s)Ledger (432 x 279 mm) QPrintDialogl_eNfLegal QPrintDialog@Legal (8.5 x 14 [ 216 x 356 k|s)%Legal (8.5 x 14 inches, 216 x 356 mm) QPrintDialogO~Letter QPrintDialogBLetter (8.5 x 11 [ 216 x 279 k|s)&Letter (8.5 x 11 inches, 216 x 279 mm) QPrintDialogg,W0eN Local file QPrintDialogxn[OK QPrintDialogbSSpPrint QPrintDialogbSSpR0eN & &Print To File ... QPrintDialogbSSpQh Print all QPrintDialogbSSpV Print range QPrintDialogbSSp bPrint selection QPrintDialogbSSpR0eN(PDF)Print to File (PDF) QPrintDialog"bSSpR0eN(Postscript)Print to File (Postscript) QPrintDialog\Wb~Tabloid QPrintDialog,Tabloid (279 x 432 k|s)Tabloid (279 x 432 mm) QPrintDialog" N vepPy:_SRMuShow facing pagesQPrintPreviewDialogf>y:b@g uviShow overview of all pagesQPrintPreviewDialogf>y:SUuShow single pageQPrintPreviewDialoge>Y'Zoom inQPrintPreviewDialog)\Zoom outQPrintPreviewDialog~AdvancedQPrintPropertiesWidgetzOSFormQPrintPropertiesWidgetuPageQPrintPropertiesWidgeth![CollateQPrintSettingsOutput_irColorQPrintSettingsOutput_irj!_ Color ModeQPrintSettingsOutputbCopiesQPrintSettingsOutputYNCopies:QPrintSettingsOutput N$RbSSpDuplex PrintingQPrintSettingsOutputzOSFormQPrintSettingsOutputpp^ GrayscaleQPrintSettingsOutputO Long sideQPrintSettingsOutputeNoneQPrintSettingsOutput yOptionsQPrintSettingsOutputQnOutput SettingsQPrintSettingsOutputuepN Pages fromQPrintSettingsOutputbSSpQh Print allQPrintSettingsOutputbSSpV Print rangeQPrintSettingsOutputSTReverseQPrintSettingsOutput b SelectionQPrintSettingsOutputwO Short sideQPrintSettingsOutputR0toQPrintSettingsOutputT y(&N)&Name: QPrintWidget...... QPrintWidgetzOSForm QPrintWidgetOMn Location: QPrintWidgetQeN(&F) Output &file: QPrintWidget \^`'(&R) P&roperties QPrintWidgetPreview QPrintWidgetbSSpg:Printer QPrintWidget|{WType: QPrintWidgetelbS_u(NSvQe[T,Could not open input redirection for readingQProcesselbS_u(NQQevQ[T-Could not open output redirection for writingQProcessNΏz N-SeSuError reading from processQProcessTz QQeeSuError writing to processQProcess z ]])nProcess crashedQProcess T/Rz Y1%Process failed to startQProcess z YteProcess operation timed outQProcessDn(forkY1%)%1!Resource error (fork failure): %1QProcessdmCancelQProgressDialogbS_Open QPushButton N-Check QRadioButtonv[W{&|{lbad char class syntaxQRegExpvmKlbad lookahead syntaxQRegExpvY lbad repetition syntaxQRegExpOu(NY1eHvryeHdisabled feature usedQRegExpeeHvQkR6epP<invalid octal valueQRegExp GR0QPR6met internal limitQRegExpb~N R0]R{&missing left delimQRegExp lg Suno error occurredQRegExp aYv~kbunexpected endQRegExpbS_epcn^Error to open databaseQSQLite2Driver N _YNRUnable to begin transactionQSQLite2Driver N cNNRUnable to commit transactionQSQLite2Driver N VnNRUnable to rollback TransactionQSQLite2Driver N bgLSUnable to execute statementQSQLite2Result N S~gUnable to fetch resultsQSQLite2ResultQsepcn^Error closing database QSQLiteDriverbS_epcn^Error opening database QSQLiteDriver N _YNRUnable to begin transaction QSQLiteDriver N cNNRUnable to commit transaction QSQLiteDriver N VnNRUnable to rollback transaction QSQLiteDriverlg gNo query QSQLiteResultSepepN S9MParameter count mismatch QSQLiteResult N ~[SepUnable to bind parameters QSQLiteResult N bgLSUnable to execute statement QSQLiteResult N SֈLUnable to fetch row QSQLiteResult N nSUnable to reset statement QSQLiteResult^Bottom QScrollBar]揹 Left edge QScrollBarTN cR Line down QScrollBarTN cRLine up QScrollBarN Nu Page down QScrollBar]Nu Page left QScrollBarSNu Page right QScrollBarN NuPage up QScrollBarOMnPosition QScrollBarS Right edge QScrollBarTN nR Scroll down QScrollBar nRR0ّ Scroll here QScrollBarT]nR Scroll left QScrollBarTSnR Scroll right QScrollBarTN nR Scroll up QScrollBarvTop QScrollBar%1]~[XW(%1: already exists QSharedMemory%1R^vY'\\N 0%1: create size is less then 0 QSharedMemory %1N [XW(%1: doesn't exists QSharedMemory%1ftok Y1%%1: ftok failed QSharedMemory%1eeHY'\%1: invalid size QSharedMemory%1: . %1: key error QSharedMemory%1.f/zzv%1: key is empty QSharedMemory%1lg DR%1: not attached QSharedMemory%1Dn\=N%1: out of resources QSharedMemory%1gCPb~%1: permission denied QSharedMemory%1Y'\gY1%%1: size query failed QSharedMemory%1|~ߘY'\PR6$%1: system-imposed size restrictions QSharedMemory%1elՕ[%1: unable to lock QSharedMemory%1N R6 .%1: unable to make key QSharedMemory%1elՋn[v.%1: unable to set key on lock QSharedMemory%1elSm[%1: unable to unlock QSharedMemory%1Unix .eNN [XW( %1: unix key file doesn't exists QSharedMemory%1g*w %2%1: unknown error %2 QSharedMemory++ QShortcutAltAlt QShortcutTBack QShortcutBackspace Backspace QShortcutBacktabBacktab QShortcutONX_: Bass Boost QShortcut\ON Bass Down QShortcutY'ONBass Up QShortcutT|SCall QShortcutCaps Lock Caps Lock QShortcutCapsLockCapsLock QShortcutN N e1Context1 QShortcutN N e2Context2 QShortcutN N e3Context3 QShortcutN N e4Context4 QShortcutCtrlCtrl QShortcutDelDel QShortcut DeleteDelete QShortcutDownDown QShortcutEndEnd QShortcut EnterEnter QShortcutEscEsc QShortcut EscapeEscape QShortcutF%1F%1 QShortcutgUr1v Favorites QShortcutlFlip QShortcutRMForward QShortcutcwHangup QShortcutHelpHelp QShortcutHomeHome QShortcutN;u Home Page QShortcutInsIns QShortcut InsertInsert QShortcut T/R (0) Launch (0) QShortcut T/R (1) Launch (1) QShortcut T/R (2) Launch (2) QShortcut T/R (3) Launch (3) QShortcut T/R (4) Launch (4) QShortcut T/R (5) Launch (5) QShortcut T/R (6) Launch (6) QShortcut T/R (7) Launch (7) QShortcut T/R (8) Launch (8) QShortcut T/R (9) Launch (9) QShortcut T/R (A) Launch (A) QShortcut T/R (B) Launch (B) QShortcut T/R (C) Launch (C) QShortcut T/R (D) Launch (D) QShortcut T/R (E) Launch (E) QShortcut T/R (F) Launch (F) QShortcutT/RN Launch Mail QShortcut T/RYZOS Launch Media QShortcutLeftLeft QShortcut N NN*YZOS Media Next QShortcut YZOSde> Media Play QShortcut N NN*YZOSMedia Previous QShortcut YZOS_U Media Record QShortcut YZOSP\kb Media Stop QShortcutMenuMenu QShortcutMetaMeta QShortcutT&No QShortcutNum LockNum Lock QShortcutNumLockNumLock QShortcutNumber Lock Number Lock QShortcut bS_URLOpen URL QShortcutPage Down Page Down QShortcutPage UpPage Up QShortcut PausePause QShortcut PgDownPgDown QShortcutPgUpPgUp QShortcut PrintPrint QShortcutPrint Screen Print Screen QShortcutR7eRefresh QShortcut ReturnReturn QShortcut RightRight QShortcutScroll Lock Scroll Lock QShortcutScrollLock ScrollLock QShortcutd}"Search QShortcut bSelect QShortcut ShiftShift QShortcutzzh<Space QShortcut{I_Standby QShortcutP\kbStop QShortcut SysReqSysReq QShortcutSystem RequestSystem Request QShortcutTabTab QShortcut\ؗ Treble Down QShortcutY'ؗ Treble Up QShortcutUpUp QShortcut\ Volume Down QShortcutY Volume Mute QShortcutY' Volume Up QShortcutf/Yes QShortcutN Nu Page downQSlider]Nu Page leftQSliderSNu Page rightQSliderN NuPage upQSliderOMnPositionQSliderN e/cvW0W@|{WAddress type not supportedQSocks5SocketEngine cN SOCKSv5g RVhQA(Connection not allowed by SOCKSv5 serverQSocks5SocketEngineNtceQs&Connection to proxy closed prematurelyQSocks5SocketEngine Ntb~ݏcConnection to proxy refusedQSocks5SocketEngine NtceConnection to proxy timed outQSocks5SocketEngine^8g RVhY1%General SOCKSv5 server failureQSocks5SocketEngine Q~dO\eNetwork operation timed outQSocks5SocketEngine NtY1%Proxy authentication failedQSocks5SocketEngineNtY1%: %1Proxy authentication failed: %1QSocks5SocketEngineNtN;g:g*b~R0Proxy host not foundQSocks5SocketEngineSOCKSrHg,5SOSOCKS version 5 protocol errorQSocks5SocketEngineN e/cvSOCKSv5T}NSOCKSv5 command not supportedQSocks5SocketEngine TTL]g TTL expiredQSocks5SocketEngine*g*wSOCKSv5Nt Nx 0x%1%Unknown SOCKSv5 proxy error code 0x%1QSocks5SocketEnginef\LessQSpinBoxfYMoreQSpinBoxSmCancelQSqlSm`vCancel your edits?QSqlxnConfirmQSqlR dDeleteQSqlR dga_UDelete this record?QSqlcQeInsertQSqlT&NoQSql O[X Save edits?QSqlfeUpdateQSqlf/YesQSqlN cOlg .vNf %1,Cannot provide a certificate with no key, %1 QSslSocketR^SSLN N e%1 Error creating SSL context (%1) QSslSocketR^SSLOݕ %1Error creating SSL session, %1 QSslSocketR^SSLOݕ%1Error creating SSL session: %1 QSslSocketSSLcbK%1Error during SSL handshake: %1 QSslSocketN }Qeg,W0Nf %1#Error loading local certificate, %1 QSslSocketN }Qeyg . %1Error loading private key, %1 QSslSocketSe%1Error while reading: %1 QSslSocketeeHbzzv}v[xRh%1 !Invalid or empty cipher list (%1) QSslSocketyg .N Qlg . %1/Private key does not certificate public key, %1 QSslSocketN QQeepcn%1Unable to write data: %1 QSslSocket%1]~[XW(%1: already existsQSystemSemaphore %1N [XW(%1: does not existQSystemSemaphore%1Dn\=N%1: out of resourcesQSystemSemaphore%1gCPb~%1: permission deniedQSystemSemaphore%1g*w %2%1: unknown error %2QSystemSemaphore N bS_cUnable to open connection QTDSDriverN Ou(epcn^Unable to use database QTDSDriverT]nR Scroll LeftQTabBarTSnR Scroll RightQTabBarsocketdO\N e/c$Operation on socket is not supported QTcpServer Y R6(&C)&Copy QTextControl |4(&P)&Paste QTextControl `bY (&R)&Redo QTextControl dm(&U)&Undo QTextControlY R6cOMn(&L)Copy &Link Location QTextControl RjR(&T)Cu&t QTextControlR dDelete QTextControl bQh Select All QTextControlbS_Open QToolButtonc N Press QToolButtonN*^sSN e/cIPv6#This platform does not support IPv6 QUdpSocket`bY Redo QUndoGroupdUndo QUndoGroup QUndoModel`bY Redo QUndoStackdUndo QUndoStackcQeUnicodecR6[W{& Insert Unicode control characterQUnicodeControlCharacterMenuLRE _YN]R0S]LQe$LRE Start of left-to-right embeddingQUnicodeControlCharacterMenuLRM N]R0ShLRM Left-to-right markQUnicodeControlCharacterMenuLRO _YN]TSv#LRO Start of left-to-right overrideQUnicodeControlCharacterMenuPDF _9QeTh<_PDF Pop directional formattingQUnicodeControlCharacterMenuRLE _YNST]]LQe$RLE Start of right-to-left embeddingQUnicodeControlCharacterMenuRLM NST]hRLM Right-to-left markQUnicodeControlCharacterMenuRLO _YNST]扆v#RLO Start of right-to-left overrideQUnicodeControlCharacterMenuZWJ [^cVhZWJ Zero width joinerQUnicodeControlCharacterMenuZWNJ [^^cVhZWNJ Zero width non-joinerQUnicodeControlCharacterMenuZWSP [^zzh<ZWSP Zero width spaceQUnicodeControlCharacterMenuelf>y: URLCannot show URL QWebFrameelf>y: MIMETYPECannot show mimetype QWebFrame eNN [XW(File does not exist QWebFrameVN:{VueetbSeNhbvR}&Frame load interruped by policy change QWebFrame lB;X^NRequest blocked QWebFrame lBSmNRequest cancelled QWebFrame%1 %2x%3 P} %1 (%2x%3 pixels)QWebPage %n N*eN %n file(s)QWebPage mRR0[WQxAdd To DictionaryQWebPagev HTTP lBBad HTTP requestQWebPage|OSBoldQWebPage^BottomQWebPagehglTbQCheck Grammar With SpellingQWebPagehgbQCheck SpellingQWebPageW(QeehgbQCheck Spelling While TypingQWebPage beN Choose FileQWebPagendgvd}"Clear recent searchesQWebPageY R6CopyQWebPageY R6VrG Copy ImageQWebPageY R6c Copy LinkQWebPageRjRCutQWebPage؋DefaultQWebPage R dR0SU\>Delete to the end of the wordQWebPage R dR0SU͙Delete to the start of the wordQWebPageeT DirectionQWebPage[WOSFontsQWebPageTGo BackQWebPageRM Go ForwardQWebPagebQTlHide Spelling and GrammarQWebPage_ueIgnoreQWebPage_ue Ignore Grammar context menu itemIgnoreQWebPagehgInspectQWebPageaY'R)OSItalicQWebPage"JavaScriptfTJ - %1JavaScript Alert - %1QWebPage"JavaScriptxn - %1JavaScript Confirm - %1QWebPage"JavaScriptcy: - %1JavaScript Prompt - %1QWebPageLTRLTRQWebPage]揹 Left edgeQWebPage W([WQxN-gb~Look Up In DictionaryQWebPageyRQIhR0WW\>'Move the cursor to the end of the blockQWebPageyRQIhR0eNg+\>*Move the cursor to the end of the documentQWebPageyRQIhR0L\>&Move the cursor to the end of the lineQWebPageyRQIhR0N NN*[W{&%Move the cursor to the next characterQWebPageyRQIhR0N NL Move the cursor to the next lineQWebPageyRQIhR0N NN*SU Move the cursor to the next wordQWebPageyRQIhR0N NN*[W{&)Move the cursor to the previous characterQWebPageyRQIhR0N NL$Move the cursor to the previous lineQWebPageyRQIhR0N NN*SU$Move the cursor to the previous wordQWebPageyRQIhR0WW)Move the cursor to the start of the blockQWebPageyRQIhR0eN_Y4,Move the cursor to the start of the documentQWebPageyRQIhR0L(Move the cursor to the start of the lineQWebPage lg b~R0smKNo Guesses FoundQWebPagelg eN bNo file selectedQWebPagelg gvd}"No recent searchesQWebPagebS_hFg Open FrameQWebPagebS_VrG Open ImageQWebPagebS_c Open LinkQWebPageW(ezSN-bS_Open in New WindowQWebPagen^OutlineQWebPageN Nu Page downQWebPage]Nu Page leftQWebPageSNu Page rightQWebPageN NuPage upQWebPage|4PasteQWebPageRTLRTLQWebPage gvd}"Recent searchesQWebPagee}QeReloadQWebPagenResetQWebPageS Right edgeQWebPageO[XVrG Save ImageQWebPageO[Xc... Save Link...QWebPageTN nR Scroll downQWebPage nRR0ّ Scroll hereQWebPageT]nR Scroll leftQWebPageTSnR Scroll rightQWebPageTN nR Scroll upQWebPaged}"QuSearch The WebQWebPage N-R0WW\>Select to the end of the blockQWebPage N-R0eN\>!Select to the end of the documentQWebPage N-R0L\>Select to the end of the lineQWebPage N-R0N NN*[W{&Select to the next characterQWebPage N-R0N NLSelect to the next lineQWebPage N-R0N NN*SUSelect to the next wordQWebPage N-R0N NN*[W{& Select to the previous characterQWebPage N-R0N NLSelect to the previous lineQWebPage N-R0N NN*SUSelect to the previous wordQWebPage N-R0WW Select to the start of the blockQWebPage N-R0eN#Select to the start of the documentQWebPage N-R0LSelect to the start of the lineQWebPagef>y:bQTlShow Spelling and GrammarQWebPagebQSpellingQWebPageP\kbStopQWebPagecNSubmitQWebPagecNQSubmit (input element) alt text for elements with no alt, title, or valueSubmitQWebPageeg,eTText DirectionQWebPage.f/NN*SNd}"v}"_0Qed}"vQs.[W3This is a searchable index. Enter search keywords: QWebPagevTopQWebPageN R~ UnderlineQWebPageg*wvUnknownQWebPageQuhgTX - %2Web Inspector - %2QWebPage f/NNH What's This?QWhatsThisAction**QWidget [b(&F)&FinishQWizard ^.R(&H)&HelpQWizardN Nke(&N)&NextQWizardN Nke(&N) >&Next >QWizard< N Nke(&B)< &BackQWizardSmCancelQWizardcNCommitQWizard~~ContinueQWizard[bDoneQWizardVGo BackQWizard^.RHelpQWizard%1 - [%2] %1 - [%2] QWorkspace Qs(&C)&Close QWorkspace yR(&M)&Move QWorkspace `bY (&R)&Restore QWorkspace Y'\(&S)&Size QWorkspace \U_(&U)&Unshade QWorkspaceQsClose QWorkspacegY'S(&X) Ma&ximize QWorkspaceg\S(&N) Mi&nimize QWorkspaceg\SMinimize QWorkspace`bY  Restore Down QWorkspace Sww(&A)Sh&ade QWorkspace`;W(gRM(&T) Stay on &Top QWorkspace2W(SXMLXfveP xXfbrzXfg_Yencoding declaration or standalone declaration expected while reading the XML declarationQXml W(NN*Y[OSveg,Xfg 3error in the text declaration of an external entityQXmlW(glvePSu$error occurred while parsing commentQXmlW(gQ[vePSu$error occurred while parsing contentQXml W(gehc|{W[NIvePSu5error occurred while parsing document type definitionQXmlW(gQC} vePSu$error occurred while parsing elementQXmlW(gS€vePSu&error occurred while parsing referenceQXmlu1m9QSverror triggered by consumerQXml*W(DTDN-N QAOu(Ygvu([OSS€;external parsed general entity reference not allowed in DTDQXml*W(\^`'Pg YQ[0!Extra content at end of document. QXmlStream^lvT}T zzXf0Illegal namespace declaration. QXmlStreameeHvXML[W{&0Invalid XML character. QXmlStreameeHvXMLT y0Invalid XML name. QXmlStreameeHvXMLrHg,[W{&N20Invalid XML version string. QXmlStreamW(XMLXfN-eeHv\^`'0%Invalid attribute in XML declaration. QXmlStreameeHv[W{&_u(0Invalid character reference. QXmlStream eeHvehc0Invalid document. QXmlStreameeHv[OSP<0Invalid entity value. QXmlStreameeHvYtcNT y0$Invalid processing instruction name. QXmlStreamW(Sep[OSXfN-g NDATA0&NDATA in parameter entity declaration. QXmlStream T}T zzv %1 RMlg Xf"Namespace prefix '%1' not declared QXmlStream_YhT~g_hN S9M0 Opening and ending tag mismatch. QXmlStreamehcev~g_0Premature end of document. QXmlStreamhmKR0]LYW[OS0Recursive entity detected. QXmlStream$W(\^`'P ^R0&Sequence ']]>' not allowed in content. QXmlStreamrzˏЈLSQAf/bT&0"Standalone accepts only yes or no. QXmlStream_Yg_vh0Start tag expected. QXmlStream"rzˏЈLO*\^`'_Ř{QsW(xNKT0?The standalone pseudo attribute must appear after the encoding. QXmlStreamaYv  Unexpected ' QXmlStream&W(Qlg heg,N-g aYv[W{& %1 0/Unexpected character '%1' in public id literal. QXmlStreamN e/cvXMLrHg,0Unsupported XML version. QXmlStream XMLXflg W(ehcv_YOMn0)XML declaration not at start of document. QXmlStream$%1 T %2 S9MNNLvY4T\>0,%1 and %2 match the start and end of a line. QtXmlPatternselՃS %1%1 cannot be retrieved QtXmlPatterns,%1ST+NW(lBx%2N-N QAvQkOMP<0E%1 contains octets which are disallowed in the requested encoding %2. QtXmlPatternsZ%1 f/NN*Y gB|{W0elbQR0Y gB|{W0Vkd bQR0OY %2 h7vS[P|{Wf/SNv0s%1 is an complex type. Casting to complex types is not possible. However, casting to atomic types such as %2 works. QtXmlPatterns%1 f/NN*eeHv %20%1 is an invalid %2 QtXmlPatterns0%1 f/kcRh_N-vNN*eeHh0g eHhN:?%1 is an invalid flag for regular expressions. Valid flags are: QtXmlPatterns$%1 f/NN*eeHvT}T zz URI0%1 is an invalid namespace URI. QtXmlPatterns(%1 f/kcRh_N-vNN*eeHj!_%2/%1 is an invalid regular expression pattern: %2 QtXmlPatterns %1N f/NN*Tlvj!gj!_T y0$%1 is an invalid template mode name. QtXmlPatterns%1 f/NN*g*wvehH|{W0%1 is an unknown schema type. QtXmlPatterns %1 f/N e/cvx0%1 is an unsupported encoding. QtXmlPatterns,%1 N f/NN*g eHv XML 1.0 [W{&0$%1 is not a valid XML 1.0 character. QtXmlPatterns %1N f/NN*YtcNvTlT y04%1 is not a valid name for a processing-instruction. QtXmlPatterns%1 N f/NN*g eHvep[WNI0"%1 is not a valid numeric literal. QtXmlPatterns@%1 N f/YtcNvg eHvhT y0[_Ř{f/P< %2 OY %30Z%1 is not a valid target name in a processing instruction. It must be a %2 value, e.g. %3. QtXmlPatterns"%1 N f/|{WN: %2 vg eHP<0#%1 is not a valid value of type %2. QtXmlPatterns%1 N f/Rvetep0$%1 is not a whole number of minutes. QtXmlPatterns(%1 N f/S[P|{W0SbQR0S[P|{W0C%1 is not an atomic type. Casting is only possible to atomic types. QtXmlPatterns8%1 N f/VQ\^`'Xf0laehH[Qery`'f/N e/cv0g%1 is not in the in-scope attribute declarations. Note that the schema import feature is not supported. QtXmlPatterns"%1 N f/|{WN: %2 vg eHP<0&%1 is not valid as a value of type %2. QtXmlPatterns%1 S9MNcbL{&%1 matches newline characters QtXmlPatterns>%1 _Ř{ %2 b %3 ߖ N W(fcb[W{&N2vg+\>0J%1 must be followed by %2 or %3, not at the end of the replacement string. QtXmlPatterns4%1 \ %n N*Sep0Vkd %2 f/eeHv0=%1 requires at least %n argument(s). %2 is therefore invalid. QtXmlPatterns6%1 gYSNg %n N*Sep0Vkd %2 f/eeHv09%1 takes at most %n argument(s). %2 is therefore invalid. QtXmlPatterns%1 u(N0%1 was called. QtXmlPatternslN ST+ %1A comment cannot contain %1 QtXmlPatternslN N %1 ~\>0A comment cannot end with a %1. QtXmlPatterns,GR0NNN*SQAW(XQueryN-Qsvg 0An %1-attribute must have a valid %2 as value, which %3 isn't. QtXmlPatterns*^&g P< %2 v %1 \^`']~XfN08An %1-attribute with value %2 has already been declared. QtXmlPatterns8T yN: %1 vSep]~ψXfN0kN*SepT y_Ř{U/N0UAn argument by name %1 has already been declared. Every argument name must be unique. QtXmlPatterns0NN*T yN: %1 v\^`']~QsW(N*QC} N-N0=An attribute by name %1 has already appeared on this element. QtXmlPatterns$NN*T yN: %1 v\^`']~ψR^01An attribute by name %1 has already been created. QtXmlPatternsRNN*\^`'pN f/NN*ehcpv[Pp0Vkd N*\^`' %1 b@W(OMnf/N Tv0dAn attribute node cannot be a child of a document node. Therefore, the attribute %1 is out of place. QtXmlPatterns%2_Ř{\SNN*[PQC} %103At least one %1 element must appear as child of %2. QtXmlPatterns"\NN*QC} %1QsW(%2NKRM0-At least one %1-element must occur before %2. QtXmlPatterns"\NN*QC} %1QsW(%2NKQ0-At least one %1-element must occur inside %2. QtXmlPatterns\g NN*~NTHs0'At least one component must be present. QtXmlPatterns*W(QC} %2v%1\^`'N-\c[NN*j!_0FAt least one mode must be specified in the %1-attribute on element %2. QtXmlPatterns0\NN*e~N_Ř{QsW(N* %1 uLPNKT0?At least one time component must appear after the %1-delimiter. QtXmlPatterns\^`'%1T%2_|kdNe0+Attribute %1 and %2 are mutually exclusive. QtXmlPatterns.\^`' %1 N N2LS VN:[QsW(gv\B0EAttribute %1 can't be serialized because it appears at the top level. QtXmlPatterns@\^`'%1N QsW(QC} %2N 0Sg %30%4ThQ\^`'f/QAv0]Attribute %1 cannot appear on the element %2. Allowed is %3, %4, and the standard attributes. QtXmlPatterns:\^`'%1N QsW(QC} %2N 0Sg %3ThQ\^`'f/QAv0YAttribute %1 cannot appear on the element %2. Allowed is %3, and the standard attributes. QtXmlPatterns:\^`'%1N QsW(QC} %2N 0Sg %3ThQ\^`'f/QAv0^Attribute %1 cannot appear on the element %2. Only %3 is allowed, and the standard attributes. QtXmlPatterns4\^`'%1N QsW(QC} %2N 0Sg hQ\^`'SNQs0VAttribute %1 cannot appear on the element %2. Only the standard attributes can appear. QtXmlPatterns\^`'%1vPelbQR0 %1 VN:[f/NN*ba|{W ^vNVkdelՈ[OS0fCasting to %1 is not possible because it is an abstract type, and can therefore never be instantiated. QtXmlPatternshmKR0sCircularity detected QtXmlPatterns %1 e[N %2 gf/eeHv0Day %1 is invalid for month %2. QtXmlPatterns*%1 ef/W( %2...%3 VNKYv0#Day %1 is outside the range %2..%3. QtXmlPatternsW(XSL-TNN- N Ou(%1t SOu(%2tb%3t0DIn an XSL-T pattern, axis %1 cannot be used, only axis %2 or %3 can. QtXmlPatterns.W(XSL-Th7_N- Qep%1N g {,N N*Sep0>In an XSL-T pattern, function %1 cannot have a third argument. QtXmlPatterns@W(XSL-Th7_N- Su(Qep%1T%2SNu(NS9M %3N SN0OIn an XSL-T pattern, only function %1 and %2, not %3, can be used for matching. QtXmlPatternsNW(XSL-Th7_N- Qep%1v{,NN*Sep_Ř{f/e[WbSؑS€ NOu(NS9M0yIn an XSL-T pattern, the first argument to function %1 must be a literal or a variable reference, when used for matching. QtXmlPatternsDW(XSL-Th7_N- Qep%1v{,NN*Sep_Ř{f/[W{&N2 NOu(NS9M0hIn an XSL-T pattern, the first argument to function %1 must be a string literal, when used for matching. QtXmlPatternsFW(N*fcb[W{&N2N- %1 Su(NlNI[g,b %2 N f/ %3MIn the replacement string, %1 can only be used to escape itself or %2, not %3 QtXmlPatternsDW(N*fcb[W{&N2N- %1 W(lg lNIveP_Ř{\NN*ep[Wߖ0VIn the replacement string, %1 must be followed by at least one digit when not escaped. QtXmlPatterns(etepdl(%1)d(%2)f/g*[NIv00Integer division (%1) by zero (%2) is undefined. QtXmlPatternsel~[R0N*RM %10+It is not possible to bind to the prefix %1 QtXmlPatternselN %1 bQR0 %20)It is not possible to cast from %1 to %2. QtXmlPatternsN Y XfRM %10*It is not possible to redeclare prefix %1. QtXmlPatterns\N S %10'It will not be possible to retrieve %1. QtXmlPatterns"N W(NOUQv[|{WpTmR\^`'0AIt's not possible to add attributes after any other kind of node. QtXmlPatterns,elN|{WN: %2 vP< %1 bQR0 %37It's not possible to cast the value %1 of type %2 to %3 QtXmlPatternsS9Mf/Y'\QN eOavMatches are case insensitive QtXmlPatterns,j!WW[QeN QsW(Qep0SؑT yXfNKRM0MModule imports must occur before function, variable, and option declarations. QtXmlPatterns(lBj!dl(%1)d(%2)f/g*[NIv00Modulus division (%1) by zero (%2) is undefined. QtXmlPatterns*%1 gf/W( %2...%3 VNKYv0%Month %1 is outside the range %2..%3. QtXmlPatternsDNN*|{WN: %1 vPOperator %1 cannot be used on atomic values of type %2 and %3. QtXmlPatterns$dO\{& %1 N u(N|{W %20&Operator %1 cannot be used on type %2. QtXmlPatterns@W(|{W %2 T %3 vS[PPu|{e n|{W_Ř{f/T N|{W b[_Ř{f/NN*[W{&N2|{W0|{W %2 f/N QAv0When casting to %1 or types derived from it, the source value must be of the same type, or it must be a string literal. Type %2 is not allowed. QtXmlPatterns:_SQep%1u(Nh7_S9Me Sep_Ř{f/SؑS€b[W{&N20vWhen function %1 is used for matching inside a pattern, the argument must be a variable reference or a string literal. QtXmlPatterns*zzv}[W{&ydN d^_S[NQsW([W{&|{N-OWhitespace characters are removed, except when they appear in character classes QtXmlPatternsrXSL-TQC} N-vXSL-T\^`'_Ř{e>W(zz(null)T}T zzN- N f/W(XSL-TT}T zzN- %1Stf/N*h7[P0iXSL-T attributes on XSL-T elements must be in the null namespace, not in the XSL-T namespace which %1 is. QtXmlPatterns*%1 ^tf/eeHv VN:^N %2 _Y0-Year %1 is invalid because it begins with %2. QtXmlPatternszzv}empty QtXmlPatternsxnRW0N exactly one QtXmlPatterns NbfY one or more QtXmlPatterns bfY zero or more QtXmlPatternsbN zero or one QtXmlPatterns]YMuted VolumeSlider %1% Volume: %1% VolumeSliderTreeLine-3.2.1/translations/treeline_de.qm000066400000000000000000003117221506556630100206000ustar00rootroot00000000000000g7{hD rm<xCMjj!%D0^$^O0KJ7c8s$H5'LH5UVE'yc wE}5~& e50KN~[w 7~D&u(F"* **y*f*g*%g*Tܷ*O*0g*5e+5t +Uh+j+Fr+ + ]+R+:+į V+i/5/s5S4;0-*uwUya~}X=2:eGD!nHlS"=6'w9ww9667D 7Agc)z]UY)3f3i`P[y-~wpM,CC(unﶰ~2}?ds#e" y$y$3E|c 7E%v--/456n6n6nO;Y d=>6s`Gx-R5]g_ cPgIpx?V|E>R-ۇv@%hQ0Z [\nwie6  ~.-+~bҮqqB<~:C]JuQp 49%o{@taU[~ T#].E>1S9;9C@D4N`bN$k'R XMs[óAaLlGaJf@g1i 5YlwpDl2CoFs͎zP}'q~o.tY&G$"H_iˮX$8Zj]2 Eh§#z2³:G֓#֓ƯY kqo^0.T%sAUi  x5~*;T~8._<$&=kK(!7+.5ޣ6a>?d@B@{pZFJɠ\8vh`}If4gNeShT]hrhx3}A`Zcb\^H?G%5LcbN)JJ_HjTa(N&.+k+%W"D!7ϑĮ$eT1לNשD5eؙY: L XKgkHfwS]!m /mNs t5d7[ѤZcyI~nB%U#CT#Cr&$&*,B.M/ //70?In3LRS;S"UZz Z]s_Phb#e,fXDfȊg#}lF2r^1IPhrqnsZVITi07~|ϥ;!^ .&I.qR&@˃8Ψ.M7ieM7uL_Ep>y>lgx4.YQ7.&k&tO0(m3P)s/0nd"g7OgU8OfCdCP[&R9T2SU=Ut\]1"IhfkkNEn]n nprX{}\6n,o]NCu/JXG #[KǨ}˛xOe"uE3r`^SfOų`3 DW'аgUt*SeU,0F1cD"1cDz9H@EFyLCW7Y[%]!bbn#BwƾWNyv{0> P" *9bAc =cc)K>Hn$ZjTz_ص©M*)|j9ߒo;\^ *;M%%s%%fx` ̇8}Cu%U[Ԥ?{޹[߂)ߗev+^mҷ )  \~? \~& ;? q#31 -- !' 4E 5 :r F LM Mg f+>h kۉ d 8J"  , ω \ji J b b* ld }s ߡ Q Z e , n ʵ; tn n" Yo e  o# e& cY { 0( . x TW M W= ,_$87 /; 4k 5rF 7* =5 ITe Ty UΆ Wܾ?$ _҉/ a cN c e uo< u5 = w5A ăc 5Ke 1_  34 :0 I I I IH{ I Iԕ I I CwF 8rE 9iy 10  , 4 6"J> 5^ .r < ^ Iy E ; t ˈ1 ĽNCI ;: Gc+ : : O p ;ZQ 5 e3 - s / G s . ' t X KK )M( -86 .25# /.y 2 %* 5>X 93 @(e/ Aq KsM K/o L.E L9Y W X{ [tn pI3 rW2 x( x( {u_ :379 ^ s  H    G Z ic^ D DR] (  ]t6 S7 o D0: k BA ~@/ ӱ t Ae ٷ ߺ KGi ~B \E,@ n` ^-g y~ A vi  ` EW J +I& P% % #D Q ll i) # '{ x (EL * O 2l* 7"3 8Ǒv ;yAI =' @|5( @ VGo dMn g#:x n/< pk! t3 t, tz v" {Bl =Q N eV hH Mc` T [F E 5 Ca 4 eP h m)a ү_ v bng DJ U1 { Y( W \ -a LV l3 '6 .c 0uT 0! 3 7y@U CQ G9. H<{ Kz9@ KRg M+ Nm ]`^l _ y a*ǚ dT ii sW :k mjc"Yefses[i(t(<-/+%0/f20>e9= +EjDH;L`o=LLL^h)V>YqZr]~Khj i?]klfcLp#MWp#qNtt/CEDL$^A=@-wtÁnrb $t :k- :`E CԕbՁedYe769xh@ #tݤpVC`Ϩ[;>h KcR(S68 q|4<@-ZHNIHM9U6Z8nH[K e3em3UiFWFr>s$Cwwr|*d{}$7f'?y2A+ӝbԲ@ t],(to2IqmzN#n#HpL3Mu4!$&|!ɟ)Җ(T~*]DsoB?4odtdRu3 6f|it&Abbrechen&Cancelcolorset&OK&OKcolorset.Button HintergrundfarbeButton background colorcolorset Button TextfarbeButton text colorcolorset"FarbeinstellungenColor Settingscolorset,unfinished">Farbschema Color Themecolorset4Anwender-definierte Farben Custom Colorscolorset4Anwender-definiertes Thema Custom themecolorsetDunkles Thema Dark themecolorset<(Voreingestelltes) SystemthemaDefault system themecolorset6Dialog fr HintergrundfarbeDialog background colorcolorset(Dialog fr TextfarbeDialog text colorcolorsetJFarbe fr nicht verfgbare FunktionenDisabled button text colorcolorset,Textfarbe deaktivierenDisabled text foreground colorcolorset&Textfarbe von LinksLink text colorcolorset({0} Farben auswhlenSelect {0} colorcolorset:Hintergrundfarbe des EintragsSelected item background colorcolorsetFVordergrundfarbe des EintragstextesSelected item text colorcolorset>Hintergrundfarbe fr TextfelderText widget background colorcolorset>Vordergrundfarbe fr TextfelderText widget foreground colorcolorset"Farben des Themas Theme Colorscolorset:Hintergrundfarbe fr TooltipsTool tip background colorcolorset:Vordergrundfarbe fr TooltipsTool tip foreground colorcolorset"&Regel hinzufgen &Add New Rule conditional&Abbrechen&Cancel conditional&Schlieen&Close conditional&Lschen&Delete conditionalFilter &beenden &End Filter conditional&Filter&Filter conditional &Laden&Load conditional&OK&OK conditional&Regel lschen &Remove Rule conditionalS&peichern&Save conditional FalschFalse conditionalSuche &Nchsten Find &Next conditional"Suche &VorherigenFind &Previous conditional Name:Name: conditional@Keine bereinstimmungen gefunden!No conditional matches were found conditionalKnotentyp Node Type conditionalRegel {0}Rule {0} conditional&Gespeicherte Regeln Saved Rules conditionalWahrTrue conditional[Alle Typen] [All Types] conditionalundand conditionalenthltcontains conditionalendet mit ends with conditionaloderor conditionalbeginnt mit starts with conditional&Anwenden&Apply configdialog&Abbrechen&Cancel configdialog&Datentyp &Data Type configdialogTyp &lschen &Delete Type configdialog,Von &Original ableiten&Derive from original configdialog&Gleichung &Equation configdialog&Feld &konfigurieren &Field Config configdialog&Feldtyp &Field Type configdialog*Erweitert &ausblenden&Hide Advanced configdialogNach &unten &Move Down configdialog&Neues Feld... &New Field... configdialog&Neuer Typ... &New Type... configdialog&OK&OK configdialog&Prfix&Prefix configdialog&Zurcksetzen&Reset configdialog&Ergebnistyp &Result Type configdialog &Alles auswhlen &Select All configdialog&Erweitert &anzeigen&Show Advanced configdialog"&Sortierbedingung&Sort Criteria configdialog&&berschrift Format &Title Format configdialogN&Leere Zeilen zwischen KnotenhinzufgenAdd &blank lines between nodes configdialogFeld hinzufgen Add Field configdialogTyp hinzufgenAdd Type configdialogDDatentypen hinzufgen oder lschenAdd or Remove Data Types configdialog:&Aufzhlungspunkte hinzufgenAdd text bullet&s configdialog:&HTML Text im Format erlaubenAllow &HTML rich text in format configdialog0Arithmetische OperatorenArithmetic Operators configdialog$Automatische TypenAutomatic Types configdialog*Verfgbare &FeldlisteAvailable &Field List configdialog$Verfgbare &FelderAvailable &Fields configdialog&Bool'sches ErgebnisBoolean Result configdialognKann keinen Datentyp lschen, der noch in Benutzung ist+Cannot delete data type being used by nodes configdialog&Icon ndern Change &Icon configdialogAnzahl Kinder Child Count configdialogKind-VerweisChild Reference configdialog Kind Typ GrenzenChild Type Limits configdialog*Auswahl &zurcksetzen Clear &Select configdialog Typ &kopieren... Co&py Type... configdialogZAusgabe &Trenner fr Kombination && Kindliste+Combination && Child List Output &Separator configdialog(VergleichsoperatorenComparison Operators configdialog0Datentypen konfigurierenConfigure Data Types configdialogTyp kopieren Copy Type configdialog ZhlenCount configdialog.&Bedingte Typen anlegenCreate Co&nditional Types configdialog Datum Date Result configdialog:&Standardwert fr neue KnotenDefault &Value for New Nodes configdialog$Standard Kind &TypDefault Child &Type configdialog&Ausdruck definierenDefine Equation configdialogDMathematischen Ausdruck definierenDefine Math Field Equation configdialogFeld &lschen Dele&te Field configdialog0Abgeleitet von &BasistypDerived from &Generic Type configdialogBeschreibung Description configdialogRichtung Direction configdialogEditorhhe Editor Height configdialog>Name des neuen Feldes eingeben:Enter new field name: configdialogBGib den Namen des neuen Typs ein:Enter new type name: configdialog.Fehler in Gleichung: {}Equation error: {} configdialog^Fehler - Zirkulrer Verweis im berechnetem Feld2Error - circular reference in math field equations configdialog"Bewerte HTML TagsEvaluate &HTML tags configdialogZusatztext Extra Text configdialog &FeldF&ield configdialog&Feldliste F&ield List configdialogFeldField configdialog&Feldliste Field &List configdialogFeldverweisField References configdialog"Dateiinfo-VerweisFile Info Reference configdialog$Richtung &umkehrenFlip &Direction configdialog"Hilfe zum &Format Format &Help configdialogIconIcon configdialog.Mathematischer Ausdruck Math Equation configdialog*&Feldliste bearbeitenModify &Field List configdialog,&Bedingte Typen ndernModify Co&nditional Types configdialog,Nach &oben verschiebenMove &Up configdialog.Nach &unten verschieben Move Do&wn configdialog,Nach &oben verschiebenMove U&p configdialogNameName configdialogLeerNone configdialog,&Anzahl der TextzeilenNum&ber of text lines configdialogAnzahl Ergebnis Number Result configdialog"Anzahl der KinderNumber of Children configdialog$Typ des O&peratorsO&perator Type configdialog&AusgabeO&utput configdialog*Liste der Oper&atorenOper&ator List configdialogOperationen Operations configdialog6Verweise zu anderen FeldernOther Field References configdialog&AusgabeformatOut&put Format configdialog&AusgabeformatOutpu&t Format configdialogHTML Ausgabe Output HTML configdialogAusgabeoptionenOutput Options configdialogVater-VerweisParent Reference configdialogVerweis&typRefere&nce Type configdialogVerweis &StufeReference &Level configdialogVerweis &TypReference &Type configdialogVerweis&stufeReference Le&vel configdialog&Feld &umbenennen...Rena&me Field... configdialog$Typ &umbenennen...Rena&me Type... configdialogFeld umbenennen Rename Field configdialogTyp umbenennen Rename Type configdialog.Umbenennen von {} nach:Rename from {} to: configdialog$Verweis auf WurzelRoot Reference configdialog Nichts auswhlen Select &None configdialog.Verweis auf sich selbstSelf Reference configdialog,Datentyp Icon zuweisenSet Data Type Icon configdialog4Typ durch Bedingung setzenSet Types Conditionally configdialog"&Sortierfelder... Sort &Keys... configdialogSortierfeldSort Key configdialogSortierfelderSort Key Fields configdialog&SuffixSuffi&x configdialog&Typliste T&ype List configdialogText OperatorenText Operators configdialogText Ergebnis Text Result configdialogXDie folgenden Zeichen sind nicht erlaubt: {},The following characters are not allowed: {} configdialog:Der Name kann nicht leer seinThe name cannot be empty configdialogRDer Name darf keine Leerzeichen enthaltenThe name cannot contain spaces configdialogLDer Name kann nicht mit "xml" beginnen The name cannot start with "xml" configdialogVDer Name muss mit einem Buchstaben beginnen!The name must start with a letter configdialogDDer Name ist bereits in VerwendungThe name was already used configdialogUhrzeit Time Result configdialog$Typ &Konfiguration Typ&e Config configdialogTypType configdialogJEine Tabelle fr &Feldwerte verwendenUse a table for field &data configdialog,[Alle Typen verfgbar][All Types Available] configdialog [Leer][None] configdialogAbsolutwertabsolute value configdialoghinzufgenadd configdialogArcus Cosinus arc cosine configdialogArcus Sinusarc sine configdialogArcus Tangens arc tangent configdialogDurchschnittaverage configdialog(Logarithmus Basis 10base-10 logarithm configdialog*Text aneinanderhngenconcatenate text configdialogJText in Kleinbuchsrtaben konvertierenconvert text to lower case configdialogFText in Grobuchstaben konvertierenconvert text to upper case configdialog Cosinus Bogenmacosine of radians configdialog$Grad nach Bogenmadegrees to radians configdialogdividierendivide configdialogIst gleichequal to configdialogFakultt factorial configdialogFliesskommazahlfloating point configdialog*dividieren mit runden floor divide configdialogvorwrtsforward configdialog>>fwd configdialogIst grer greater than configdialog,Ist grer oder gleichgreater than or equal to configdialogHhere Ganzzahlhigher integer configdialogxErsetze in 1. Argument das 2. Argument durch das 3. Argument(in 1st arg, replace 2nd arg with 3rd arg configdialogTText verbinden mit 1. Argument als Trenner$join text using 1st arg as separator configdialogIst kleiner less than configdialog.Ist kleiner oder gleichless than or equal to configdialogLogisches Und logical and configdialogLogisches Oder logical or configdialog&Niedrigere Ganzzahl lower integer configdialogMaximummaximum configdialogMinimumminimum configdialog modulomodulus configdialogmultiplizierenmultiply configdialogEulersche Zahlnatural log constant configdialog.Natrlicher Logarithmusnatural logarithm configdialog Ist nicht gleich not equal to configdialogPI pi constant configdialogexponierenpower configdialog$Bogenma nach Gradradians to degrees configdialog<<rev configdialogrckwrtsreverse configdialog(Runden auf n Stellenround to num digits configdialogSinus Bogenmasine of radians configdialogQuadratwurzel square root configdialogabziehensubtract configdialogsummieren sum of items configdialog Tangens Bogenmatangent of radians configdialogPWahr, wenn 1.Argument 2.Argument enthlt%true if 1st text arg contains 2nd arg configdialogZWahr, wenn 1. Argument mit 2. Argument endet &true if 1st text arg ends with 2nd arg configdialog\Wahr, wenn 1. Argument mit 2. Argument beginnt(true if 1st text arg starts with 2nd arg configdialogJWahrer Wert, Bedingung, Falscher Wert"true value, condition, false value configdialog.Abgeschnittene Ganzzahltruncated integer configdialogDatei &suchen&Browse for File dataeditors&Abbrechen&Cancel dataeditors&Gehe zu Ziel &Go to Target dataeditors&OK&OK dataeditors&Verweis ffnen &Open Link dataeditors&ffne Bild &Open Picture dataeditors6Klicke Verweis Ziel im Baum(Click link target in tree) dataeditorsAbsolutAbsolute dataeditorsAdresseAddress dataeditorsVerweis lschen Clear &Link dataeditorsAnzeigename Display Name dataeditors Externer Verweis External Link dataeditors$Verzeichnis AngabeFile Path Type dataeditors Interner Verweis Internal Link dataeditors&&Verzeichnis ffnen Open &Folder dataeditors Verweis auf Bild Picture Link dataeditorsRelativRelative dataeditors SchemaScheme dataeditors"Auf &heute setzen Set to &Now dataeditorsHeutiges &Datum Today's &Date dataeditorsDVerweis zu externer TreeLine DateiTreeLine - External Link File dataeditors$TreeLine BilddateiTreeLine - Picture File dataeditorsVerweislink dataeditors&Spalten&Columnsexportsx&Komma-getrennte Tabelle (CSV) der Nachkommen (Nummern Grad);&Comma delimited (CSV) table of descendants (level numbers)exports&Gesamter Baum &Entire treeexports &HTML&HTMLexports:&HTML formatierte Lesezeichen&HTML format bookmarksexports8einschlielich Wurzel Knoten&Include root nodesexports&ODF Struktur &ODF Outlineexports:Altes TreeLine Format (2.0.x)&Old TreeLine (2.0.x)exports2&Nur geffnete Kindknoten&Only open node childrenexports(&Einzelne HTML Seite&Single HTML pageexports2&Titelzeile mit Tabulator&Tabbed title textexports &Text&Textexports"TreeLine Teilbaum&TreeLine SubtreeexportsT&Unformatierte Ausgabe des gesamten Textes&Unformatted output of all textexports:&XBEL formatierte Lesezeichen&XBEL format bookmarksexports &XML (generisch)&XML (generic)exports&Lesezeichen Book&marksexportsLesezeichen Bookmarksexports4Ausgabe Unterformat whlenChoose export format subtypeexports(Ausgabeformat whlenChoose export format typeexports,Ausgabeoptionen whlenChoose export optionsexportstKomma-&getrennte Tabelle (CSV) der Kinder (einzelner Grad)7Comma &delimited (CSV) table of children (single level)exportsFehler - Kann nicht auf nicht gespeicherte TreeLine Datei verweisen. Speichere die Datei und versuche es erneut.FError - cannot link to unsaved TreeLine file. Save the file and retry.exportsFehler - Export Vorlage nicht gefunden. berprfe deine TreeLine Installation.JError - export template files not found. Check your TreeLine installation.exportsDatei Export File Exportexports@&Kopf- und Fuzeile einschlieenInclude &print header && footerexportsLive Baum Ansicht, verlinkt mit der TreeLine Datei (fr Web Server)8Live tree view, linked to TreeLine file (for web server)exportshLive Baum Ansicht, eine Datei (Daten eingeschlossen)+Live tree view, single file (embedded data)exports6Mehrere HTML &DatentabellenMultiple HTML &data tablesexportsTMehrere HTML &Seiten mit Navigationsleiste)Multiple HTML &pages with navigation paneexportsVSie mssen Knoten vor dem Export auswhlen.!Must select nodes prior to exportexports:&Stufen der NavigationsleisteNavigation pane &levelsexportsAndere Optionen Other Optionsexports ElternParentexports,&Ausgewhlte TeilbumeSelected &branchesexports&Ausgewhlte &KnotenSelected &nodesexportsTEinzelne &HTML Seite mit Navigationsleiste&Single &HTML page with navigation paneexportsfTab-&getrennte Tabelle der Kinder (&einzelner Grad)0Tab &delimited table of children (&single level)exportsTree&Line Tree&LineexportsJTreeLine - Exportiere Generisches XMLTreeLine - Export Generic XMLexports4TreeLine - Exportiere HTMLTreeLine - Export HTMLexportsLTreeLine - Exportiere HTML Lesezeichen TreeLine - Export HTML Bookmarksexports<TreeLine - Exportiere ODF TextTreeLine - Export ODF Textexports4TreeLine - Exportiere TextTreeLine - Export Plain TextexportsDTreeLine - Exportiere Text TabelleTreeLine - Export Text TablesexportsNTreeLine - Exportiere TextberschriftenTreeLine - Export Text TitlesexportsNTreeLine - Exportiere TreeLine Teilbaum"TreeLine - Export TreeLine SubtreeexportsLTreeLine - Exportiere XBEL Lesezeichen TreeLine - Export XBEL BookmarksexportsWarnung - kein relativer Pfad von "{0}" nach "{1}". Weitermachen mit absolutem Pfad?LWarning - no relative path from "{0}" to "{1}". Continue with absolute path?exports&Was wird exportiertWhat to Exportexports"." Zeichen .."." Character .. fieldformat"/" Zeichen //"/" Character // fieldformat00 oder 1 Wiederholung ?0 Or 1 Repetitions ? fieldformat:0 oder mehr Wiederholungen *0 Or More Repetitions * fieldformat:1 oder mehr Wiederholungen +1 Or More Repetitions + fieldformat AM/PMAM/PM %p fieldformat*Beliebiges Zeichen .Any Character . fieldformat Auto Auswahlfeld AutoChoice fieldformat*Auto-KombinationsfeldAutoCombination fieldformatBooleanBoolean fieldformat Grobuchstabe ACapital Letter A fieldformat2Groe rmische Ziffer ICapital Roman Numeral I fieldformatAuswahlfeldChoice fieldformat Kombinationsfeld Combination fieldformat"Komma Trenner \,Comma Separator \, fieldformat DatumDate fieldformatDatum/ZeitDateTime fieldformat,Tag (1 oder 2 Ziffern)Day (1 or 2 digits) %-d fieldformatTag (2 Ziffern)Day (2 digits) %d fieldformat4Tag des Jahres (1 bis 366)Day of year (1 to 366) %-j fieldformatDezimalkomma ,Decimal Comma , fieldformatDezimalpunkt .Decimal Point . fieldformat*Anzahl der NachkommenDescendantCount fieldformatNZiffer oder Leertaste (Extern) <space>!Digit or Space (external)  fieldformat"Punkt Trenner \.Dot Separator \. fieldformatTexteende $ End of Text $ fieldformat6Escape fr Sonderzeichen \Escape a Special Character \ fieldformat"Beispiel 1/2/3/4Example 1/2/3/4 fieldformat$Exponent (Gro) EExponent (capital) E fieldformat&Exponent (Klein) eExponent (small) e fieldformat Externer Verweis ExternalLink fieldformat>Stunde (0-23, 1 oder 2 Ziffern)Hour (0-23, 1 or 2 digits) %-H fieldformat2Stunde (00-23, 2 Ziffern)Hour (00-23, 2 digits) %H fieldformat2Stunde (01-12, 2 Ziffern)Hour (01-12, 2 digits) %I fieldformat>Stunde (1-12, 1 oder 2 Ziffern)Hour (1-12, 1 or 2 digits) %-I fieldformatHtmlTextHtmlText fieldformat Interner Verweis InternalLink fieldformat Stufentrenner /Level Separator / fieldformat*Kleinbuchstabe [a-z]Lower Case Letters [a-z] fieldformatMathematischMath fieldformat0Microsekunde (6 Ziffern)Microseconds (6 digits) %f fieldformat2Minute (1 oder 2 Ziffern)Minute (1 or 2 digits) %-M fieldformat$Minute (2 Ziffern)Minute (2 digits) %M fieldformat0Monat (1 oder 2 Ziffern)Month (1 or 2 digits) %-m fieldformat"Monat (2 Ziffern)Month (2 digits) %m fieldformatMonat AbkrzungMonth Abbreviation %b fieldformatMonat Name Month Name %B fieldformat(Keine Ziffer [^0-9]Not a Number [^0-9] fieldformat HeuteNow fieldformat NummerNumber fieldformatZiffer 1Number 1 fieldformat Nummer Numbering fieldformatEinzeiler OneLineText fieldformat&Optionale Ziffer #Optional Digit # fieldformat0Optionales Vorzeichen -Optional Sign - fieldformatOder |Or | fieldformatLGliederungsbeispiel I../A../1../a)/i)!Outline Example I../A../1../a)/i) fieldformatBildPicture fieldformat$Regulrer AusdruckRegularExpression fieldformat.Erforderliche Ziffer 0Required Digit 0 fieldformat8Erforderliches Vorzeichen +Required Sign + fieldformat4Sekunde (1 oder 2 Ziffern)Second (1 or 2 digits) %-S fieldformat&Sekunde (2 Ziffern)Second (2 digits) %S fieldformat8berschrift Beispiel 1.1.1.1Section Example 1.1.1.1 fieldformat$Sektionstrenner .Section Separator . fieldformatTrenner / Separator / fieldformat0Menge von Ziffern [0-9]Set of Numbers [0-9] fieldformat"Kleinbuchstabe aSmall Letter a fieldformat2Kleine rmische Ziffer iSmall Roman Numeral i fieldformatFLeertaste Trenner (Intern) <space>"Space Separator (internal)  fieldformat4Text, Leerzeichen getrennt SpacedText fieldformatW/FT/F fieldformatTextText fieldformatZeitTime fieldformat(Grobuchstabe [A-Z]Upper Case Letters [A-Z] fieldformat.Wochennummer (0 bis 53)Week Number (0 to 53) %-U fieldformat&Wochentag AbkrzungWeekday Abbreviation %a fieldformatWochentag NameWeekday Name %A fieldformatJ/NY/N fieldformat Jahr (2 Ziffern)Year (2 digits) %y fieldformat Jahr (4 Ziffern)Year (4 digits) %Y fieldformatwahr/falsch true/false fieldformatja/neinyes/no fieldformat falschfalse genbooleanneinno genbooleanwahrtrue genbooleanjayes genbooleanAlle Dateien All Files globalref*Alle Treeline DateienAll TreeLine Files globalref4CSV Datei (Komma-getrennt)CSV (Comma Delimited) Files globalrefHTML Dateien HTML Files globalrefODF DateienODF Text Files globalref*Alte Treeline DateienOld TreeLine Files globalrefPDF Dateien PDF Files globalrefText Dateien Text Files globalref TreeLine DateienTreeLine Files globalref<TreeLine Dateien (komprimiert)TreeLine Files - Compressed globalref@TreeLine Dateien (verschlsselt)TreeLine Files - Encrypted globalrefTreepad Dateien Treepad Files globalrefXML Dateien XML Files globalrefSuchen:  Find: helpview&Zurck&Backhelpview&Vorwrts&Forwardhelpview(&Eigenes Verzeichnis&Homehelpview &Vorwrts Suchen Find &Nexthelpview"&Rckwrts SuchenFind &Previoushelpview&Text nicht gefundenText string not foundhelpviewWerkzeugeToolshelpviewn"{0}" ist keine TreeLine Datei. Importfilter verwenden?:"{0}" is not a valid TreeLine file. Use an import filter?importsNGenerisches &XML (Keine TreeLine Datei) &Generic XML (non-TreeLine file)importsD&HTML Lesezeichen (Mozilla Format) &HTML bookmarks (Mozilla Format)importsb&Mit Tabulator eingerckter Text, Knoten je Zeile%&Tab indented text, one node per lineimportsF&XML Lesezeichendatei (XBEL-Format)&XML bookmarks (XBEL format)importsLESEZEICHENBOOKMARKimportsDFehler im CSV Format bei Zeile {0}Bad CSV format on Line {0}importsLesezeichen Bookmarksimports0Import Methode auswhlenChoose Import MethodimportsKo&mma-getrennter (CSV) Text Tabelle mit Stufe Spalte && Kopfzeile ReiheACo&mma delimited (CSV) text table with level column && header rowimportsdKo&mma-getrennter (CSV) Text Tabelle mit Kopfzeile1Comma delimited (CSV) text table &with header rowimportsFFehler - Kann Datei {0} nicht lesenError - could not read file {0}importsBFehler - ungltiges Format in {0}Error - improper format in {0}importsVERZEICHNISFOLDERimportsImport Datei Import FileimportsUngltige Datei Invalid Fileimports@Falsche Ebene Nummer on line {0} Invalid level number on line {0}imports6Fehlerhafte Ebenen StrukturInvalid level structureimportsVerweisLinkimportsFAlte Tree&Line Datei (1.x oder 2.x)Old Tree&Line File (1.x or 2.x)imports>Open &Document (ODF) GliederungOpen &Document (ODF) outlineimports AndereOtherimportsHText &Blcke (Beendet mit Leerzeile)-Plain text ¶graphs (blank line delimited)importsZNur Text, ein &Knoten pro Zeile (CR getrennt)-Plain text, one &node per line (CR delimited)importsTRENNER SEPARATORimportsTABELLETABLEimportsNTabulator getrennter Text mit Kopfzeile)Tab delimited text table with header &rowimportsTextTextimportsDZu viele Eintrge in der Zeile {0}Too many entries on Line {0}imports.TreeLine - Import DateiTreeLine - Import Fileimports2Treepad &Datei (nur Text)Treepad &file (text nodes only)imports|Verweise auf Kinder mssen in einer Funktion kombiniert werden/Child references must be combined in a functionmatheval,Ungltige Zeichen "{}"Illegal "{}" charactersmatheval.Ungltige Funktion: {0}Illegal function present: {0}mathevalNUngltiger Objekttyp oder Operator: {0}$Illegal object type or operator: {0}matheval8Ungltige Syntax in AusdruckIllegal syntax in equationmatheval&Anwenden&Apply miscdialogs&Abbrechen&Cancel miscdialogs&Schlieen&Close miscdialogsFilter &Ende &End Filter miscdialogs&Gesamter Baum &Entire tree miscdialogs&Filter&Filter miscdialogsSuche &Nchster &Find Next miscdialogs&Vorwrts&Forward miscdialogs&Ignorieren&Ignore and skip miscdialogs&Schlsselworte &Key words miscdialogs&Knotentyp &Node Type miscdialogs&OK&OK miscdialogs<&Vordefinierte Schlsselfelder&Predefined Key Fields miscdialogs&&Regulrer Ausdruck&Regular expression miscdialogs&Ersetzen&Replace miscdialogsb&Nummerierung fr nchste Geschwister neu starten"&Restart numbers for next siblings miscdialogs4&Standard wiederherstellen&Restore Defaults miscdialogs&Rckwrts&Reverse miscdialogs&Suchtext &Search Text miscdialogs&&Kinder der Auswahl&Selection's children miscdialogsNur &Titel &Titles only miscdialogs&Symbolleisten &Toolbars miscdialogs@&Leere Felder als Null behandeln&Treat blank fields as zeros miscdialogs<&Standard Schriftart verwenden&Use app default font miscdialogs:Datei&komprimierung verwenden&Use file compression miscdialogs8&System Schriftart verwenden&Use system default font miscdialogs--Trenner-- --Separator-- miscdialogsEin schwerer Fehler ist aufgetreten. TreeLine kann sich in einem instabilen Zustand befinden. Empfehlung, die Datei unter einem anderen Namen zu speichern und TreeLine neu zu starten. Das Debug Info unterhalb kann kopiert werden und per Mail an doug101@bellz.org geschickt werden zusammen mit Erluterungen, unter welchen Umstnden, der Fehler auftrat.A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances.  miscdialogs,&Verfgbare FunktionenA&vailable Commands miscdialogs Jedes &Vorkommen Any &match miscdialogs$StandardschriftartApp Default Font miscdialogsLsche &Taste Clear &Key miscdialogs*Schriftarten AnpassenCustomize Fonts miscdialogs6Symbolleisten konfigurierenCustomize Toolbars miscdialogs DatenData miscdialogsDaten Men Data Menu miscdialogs6Standard - Einzeiliger TextDefault - Single Line Text miscdialogsBearbeitenEdit miscdialogsBearbeiten Men Edit Menu miscdialogs*Schriftart fr EditorEditor View Font miscdialogsDPasswort der verschlsselten DateiEncrypted File Password miscdialogsLFehler - Ungltiger regulrer Ausdruck"Error - invalid regular expression miscdialogsBFehler - Ersetzung nicht mglich Error - replacement failed miscdialogsGanzer &Satz F&ull phrase miscdialogs FelderFields miscdialogs DateiFile miscdialogsDatei Men File Menu miscdialogs&Datei EigenschaftenFile Properties miscdialogs"Datei Speicherung File Storage miscdialogs FilterFilter miscdialogs SuchenFind miscdialogsSuche &Nchster Find &Next miscdialogs Suche &VorherigeFind &Previous miscdialogs&Suchen und ErsetzenFind and Replace miscdialogs FormatFormat miscdialogsFormat Men Format Menu miscdialogsGesamte &Daten Full &data miscdialogsGanze &Worte Full &words miscdialogs\Behandlung von Knoten ohne Nummerierungsfelder'Handling Nodes without Numbering Fields miscdialogs HilfeHelp miscdialogsHilfe Men Help Menu miscdialogs Wie wird gesucht How to Search miscdialogsJKnoten der ersten Ebene einschliessenInclude top-level nodes miscdialogs&Ganze WorteKey full &words miscdialogs0Taste {0} bereits belegtKey {0} is already used miscdialogsTastaturkrzelKeyboard Shortcuts miscdialogsJSprachcode oder Wrterbuch (optional)&Language code or dictionary (optional) miscdialogsGroe Icons Large Icons miscdialogs&Mathematisches Feld Math Fields miscdialogs.Nach &unten verschieben Move &Down miscdialogs,Nach &oben verschiebenMove &Up miscdialogs&Felder N&ode Fields miscdialogsKein MenNo menu miscdialogsDKeine Nummerierungsfelder gefunden,No numbering fields were found in data types miscdialogs KnotenNode miscdialogsKnoten&titel Node &Titles miscdialogsKnoten Men Node Menu miscdialogs,Schriftart fr AusgabeOutput View Font miscdialogs&Regulrer &AusdruckRe&gular expression miscdialogs*Passwort wiederholen:Re-Type Password: miscdialogs>Passworte stimmen nicht bereinRe-typed password did not match miscdialogsBPasswort fr diese Sitzung merken%Remember password during this session miscdialogs&Alle Ersetzen Replace &All miscdialogs&{0} Stellen ersetztReplaced {0} matches miscdialogsErsetzungs&textReplacement &Text miscdialogs,Nummerierung &umkehrenReserve &numbers miscdialogsWurzelelement Root Node miscdialogs:Suchtext "{0}" nicht gefundenSearch string "{0}" not found miscdialogs:Suchtext "{0}" nicht gefundenSearch text "{0}" not found miscdialogs,Ausgewhlte &TeilbumeSelected &branches miscdialogsN&Geschwister der ausgewhlten TelibumeSelection's &siblings miscdialogsD&Kinder der ausgewhlten TeilbumeSelection's childre&n miscdialogsKleine Icons Small Icons miscdialogsSortierrichtungSort Direction miscdialogsSortiermethode Sort Method miscdialogs Konten sortieren Sort Nodes miscdialogs&Rechtschreibprfung Spell Check miscdialogs2&Symbolleisten FunktionenTool&bar Commands miscdialogs&Symbolleisten&gre Toolbar &Size miscdialogs(Anzahl SymbolleistenToolbar Quantity miscdialogsWerkzeugTools miscdialogsWerkzeug Men Tools Menu miscdialogs4Schriftart fr BaumanzeigeTree View Font miscdialogs4TreeLine - Schwerer FehlerTreeLine - Serious Error miscdialogs*TreeLine NummerierungTreeLine Numbering miscdialogs4Passwort fr {0} eingeben:Type Password for "{0}": miscdialogs$Passwort eingeben:Type Password: miscdialogs*Nummerierung erneuernUpdate Node Numbering miscdialogs>Datei&verschlsselung verwendenUse file &encryption miscdialogsAnsichtView miscdialogsAnsicht Men View Menu miscdialogs*Nach was wird gesuchtWhat to Search miscdialogs"Was wird sortiert What to Sort miscdialogs0Was soll erneuert werdenWhat to Update miscdialogsFensterWindow miscdialogsFenster Men Window Menu miscdialogsFLeere Passwrter sind nicht erlaubt'Zero-length passwords are not permitted miscdialogs[Alle Felder] [All Fields] miscdialogs[Alle Typen] [All Types] miscdialogsNameName nodeformat^Aktiviere den Daten Editor bei schwebender Maus$Activate data editors on mouse hoveroptiondefaultsAussehen Appearanceoptiondefaults.Automatisches Speichern Auto SaveoptiondefaultsZDie zuletzt benutzte Datei automatisch ffnen!Automatically open last file usedoptiondefaults^Einrckung fr Kinder (In Schriftart Einheiten)+Child indent offset (in font height units) optiondefaults>Klick auf Knoten zum UmbenennenClick node to renameoptiondefaults<Formate im BearbeitungsfensterData Editor Formatsoptiondefaults"DatumsdarstellungDatesoptiondefaults*Verfgbare FunktionenFeatures Availableoptiondefaults Erster WochentagFirst day of weekoptiondefaultsFreitagFridayoptiondefaultshDruckoptimierte TreeLine JSON Dateien mit Einrckung)Indent (pretty print) TreeLine JSON filesoptiondefaultsrBegrenzung der Hhe des Dateneditors auf die Fenstergre'Limit data editor height to window sizeoptiondefaultsLMinimiere Programm in die Systemleiste#Minimize application to system trayoptiondefaultsjMinuten zwischen Speichervorgngen (0 fr Abschalten)+Minutes between saves (set to 0 to disable)optiondefaults MontagMondayoptiondefaultsBAnzahl zuletzt geffneter Dateien(Number of recent files in the file menuoptiondefaultsPAnzahl der mglichen WiederherstellungenNumber of undo levelsoptiondefaults<ffne Dateien in neuem FensterOpen files in new windowsoptiondefaults2Zuletzt geffnete Dateien Recent FilesoptiondefaultslLsche alle nicht vorhandenen aktuellen Datei-Eintrge'Remove inaccessible recent file entriesoptiondefaultsNNeue Knoten nach dem Anlegen umbenennenRename new nodes when createdoptiondefaultsDFenstereinteilung wiederherstellen Restore previous window geometryoptiondefaultstBaumansicht von krzlich geffneten Dateien wierherstellen(Restore tree view states of recent filesoptiondefaultsSamstagSaturdayoptiondefaultsDZeige Breadcrumb Vorfahren AnsichtShow breadcrumb ancestor viewoptiondefaultsXZeige Kind Ausschnitt in der rechten Ansicht#Show child pane in right hand viewsoptiondefaultsFUnterknoten in der Ansicht anzeigenShow descendants in output viewoptiondefaultsBIcons in der Baumansicht anzeigenShow icons in the tree viewoptiondefaultsfMathematische Felder im Bearbeiten Fenster anzeigen&Show math fields in the Data Edit viewoptiondefaultsdNummerierungsfelder im Bearbeiten Fenster anzeigen+Show numbering fields in the Data Edit viewoptiondefaultsProgrammstartStartup ConditionoptiondefaultsSonntagSundayoptiondefaultsDonnerstagThursdayoptiondefaultsZeitdarstellungTimesoptiondefaultsXVerschieben von Bumen mit der Maus erlaubenTree drag && drop availableoptiondefaultsDienstagTuesdayoptiondefaults@Speicher fr Wiederherstellungen Undo MemoryoptiondefaultsMittwoch Wednesdayoptiondefaults&Abbrechen&Canceloptions&OK&OKoptions2Ablage Konfigurationsfile"Choose configuration file locationoptionsVProgrammverzeichnis (fr portablen Einsatz)$Program directory (for portable use)options>Benutzerverzeichnis (empfohlen)#User's home directory (recommended)optionsNFehler beim Initialisieren des DruckersError initializing printer printdata4TreeLine - PDF ExportierenTreeLine - Export PDF printdataWarnung: Randeinstellung werden vom derzeitigen Drucker nicht untersttzt. Sollen die Einstellungen berichtigt werden?JWarning: Margin settings unsupported on current printer. Save adjustments? printdata Warnung: Seitengre und Randeinstellung werden vom derzeitigen Drucker nicht untersttzt. Sollen die Einstellungen berichtigt werden?]Warning: Page size and margin settings unsupported on current printer. Save page adjustments? printdataWarnung: Seitengre werden vom derzeitigen Drucker nicht untersttzt. Sollen die Einstellungen berichtigt werden?KWarning: Page size setting unsupported on current printer. Save adjustment? printdata&Unten:&Bottom: printdialogs&Abbrechen&Cancel printdialogs<Linien zu den Kindern zeichnen&Draw lines to children printdialogsGesamter Baum &Entire tree printdialogs&Schriftart&Font printdialogsSchrift&auswahl&Font Selection printdialogs2Allgemeine &Einstellungen&General Options printdialogs Kopfzeile &Links &Header Left printdialogs&Kopf-/Fuzeile&Header/Footer printdialogs2Wurzelelement hinzunehmen&Include root node printdialogs|Das erste Unterelement mit dem Elternelement zusammen anzeigen&Keep first child with parent printdialogs&Links:&Left: printdialogsSpaltenanzahl&Number of columns printdialogs&OK&OK printdialogsPrfi&x&Prefix printdialogs&Drucken... &Print... printdialogs&Rechts:&Right: printdialogs&Suffix&Suffix printdialogs &Oben:&Top: printdialogs&Einheiten&Units printdialogsL&TreeLine Ausgabe Schriftart verwenden&Use TreeLine output view font printdialogs&Breite:&Width: printdialogs"A3 (279 420 mm)A3 (279 x 420 mm) printdialogs"A4 (210 297 mm)A4 (210 x 297 mm) printdialogs"A5 (148 210 mm)A5 (148 x 210 mm) printdialogs>AaBbCcDcEeFfGg...TtUuVvWwXxYyZzAaBbCcDdEeFfGg...TtUuVvWvXxYyZz printdialogsZentimeter (cm)Centimeters (cm) printdialogsSpaltenColumns printdialogs0Benutzerdefinierte Gre Custom Size printdialogs&standard Schriftart Default Font printdialogsfFehler: Seitengre oder Seitenrnder sind ungltig(Error: Page size or margins are invalid printdialogsExtratext Extra Text printdialogs0Gegenberliegende Seiten Facing Pages printdialogsEigenschaftenFeatures printdialogs FelderFiel&ds printdialogsFeldf&ormat Field For&mat printdialogs(Feldformat fr "{0}"Field Format for "{0}" printdialogsSeite anpassenFit Page printdialogsBreite anpassen Fit Width printdialogsSchrifts&til Font st&yle printdialogs&Fuzeile:Foot&er: printdialogs&Fuzeile Links Footer &Left printdialogsFuzeile M&itteFooter Ce&nter printdialogs"Fusszeile &Rechts Footer Righ&t printdialogs,&Hilfe zu den Formaten Format &Help printdialogs&Kopfzeile:He&ader: printdialogs"Kopfzeile &Rechts Header &Right printdialogs Kopfzeile Mitt&eHeader C&enter printdialogs$Kopf- und FuzeileHeader and Footer printdialogs &Hhe:Height: printdialogsInch (in) Inches (in) printdialogs,Bercksichtigte KnotenIncluded Nodes printdialogsEinrckenIndent printdialogsVAbstand beim Einrcken (Einheit Zeilenhhe)"Indent Offse&t (line height units) printdialogs&Querformat Lan&dscape printdialogs*Legal (8.5 14 Inch)Legal (8.5 x 14 in.) printdialogs,Letter (8.5 11 Inch)Letter (8.5 x 11 in.) printdialogs RnderMargins printdialogsMillimeter (mm)Millimeters (mm) printdialogsNchste Seite Next Page printdialogs@Nur Kinder von geffneten KnotenOnl&y open node children printdialogsOrientierung Orientation printdialogsAusgabeformatOutput &Format printdialogs&Seiteneinstellungen Page &Setup printdialogsPapiergre Paper &Size printdialogs&Hochformat Portra&it printdialogsVorherige Seite Previous Page printdialogsDruckenPrint printdialogs"Druck&vorschau...Print Pre&view... printdialogsDruckvorschau Print Preview printdialogs$Druckeinstellungen Print Setup printdialogs$DruckeinstellungenPrinting Setup printdialogsBeispielSample printdialogsWhle &DruckerSelect &Printer printdialogs(Schriftart auswhlen Select Font printdialogs*Ausgewhlte TeilbumeSelected &branches printdialogs$Ausgewhlte KnotenSelected &nodes printdialogs &GreSi&ze printdialogsEinzelne Seite Single Page printdialogs2Abstand zwischen &SpaltenSpace between colu&mns printdialogs,Tabloid (11 17 Inch)Tabloid (11 x 17 in.) printdialogs(TreeLine PDF DruckerTreeLine PDF Printer printdialogs"Was wird gedruckt What to print printdialogsVergrernZoom In printdialogsVerkleinernZoom Out printdialogs&Hinzufgen&Add spellcheck&Abbrechen&Cancel spellcheck"&Alles Ignorieren &Ignore All spellcheck&Ersetzen&Replace spellcheck<Hinzufgen in &KleinbuchstabenAdd &Lowercase spellcheckKontext:Context: spellcheckKann weder aspell.exe, ispell.exe oder hunspell.exe finden. Speicherort suchen?QCould not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? spellcheckRechtschreibprfung fr den Zweig beendet. Wieder von oben anfangen? 3Finished checking the branch Continue from the top? spellcheck6Rechtschreibprfung beendetFinished spell checking spellcheck&IgnorierenIgnor&e spellcheck\Suche aspell.exe, ispell.exe oder hunspell.exe-Locate aspell.exe, ipsell.exe or hunspell.exe spellcheck&Nicht im WrterbuchNot in Dictionary spellcheck Programm (*.exe)Program (*.exe) spellcheckAlles E&rsetzen Re&place All spellcheck&Rechtschreibprfung Spell Check spellcheckBFehler in der RechtschreibprfungSpell Check Error spellcheckVorschlge Suggestions spellcheck8TreeLine RechtschreibprfungTreeLine Spell Check spellcheckFehler bei der Rechtschreibprfung. Stellen Sie sicher, dass aspell, ispell oder hunspell installiert istLTreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed spellcheck Wort:Word: spellcheckAuswahl im BaumSelect in Tree titlelistview KugelnBullets treeformatsKinderTyp ChildType treeformatsunfinishedChildTypeLimit treeformatsBedingungenConditionalRule treeformatsSTANDARDDEFAULT treeformatsunfinishedEvalHtml treeformatsFELDFIELD treeformats DATEIFILE treeformatsFELDTYP FieldType treeformatsFormat">FormatFormat treeformatsHTML-Format FormatHtml treeformatsGenerischerTyp GenericType treeformatsIcon">IconIcon treeformatsAnfangswert InitialValue treeformats$ListenTrennzeichen ListSeparator treeformats$ZeilennummerierungNumLines treeformatsAusgabeformat OutputFormat treeformats PrefixPrefix treeformats$AufwrtsSortierten SortForward treeformats Sortierschlssel SortKeyNum treeformatsZwischenraum SpaceBetween treeformats SuffixSuffix treeformatsTYPTYPE treeformatsTabelleTable treeformatsTitelformat TitleFormat treeformats&Fettschrift &Bold Fonttreelocalcontrol&Kopieren&CopytreelocalcontrolKnoten &lschen &Delete NodetreelocalcontrolTrenne Klone&Detach Clonestreelocalcontrol&Exportieren... &Export...treelocalcontrol(&Externer Verweis...&External Link...treelocalcontrol"&Schriftart Gre &Font Sizetreelocalcontrol"Knoten &einrcken &Indent Nodetreelocalcontrol&Kursivschrift &Italic Fonttreelocalcontrol,Nach &oben verschieben&Move Uptreelocalcontrol&Neues Fenster &New WindowtreelocalcontrolEin&fgen&Pastetreelocalcontrol&Drucken... &Print...treelocalcontrol"W&iederherstellen&Redotreelocalcontrol*Erstelle Verweise neu&Regenerate Referencestreelocalcontrol&Umbenennen&RenametreelocalcontrolS&peichern&Savetreelocalcontrol&Knoten&typ zuweisen&Set Node Typetreelocalcontrol.&Rechtschreibprfung...&Spell Check...treelocalcontrol&Rckgngig&Undotreelocalcontrol"Knoten &ausrcken&Unindent Nodetreelocalcontrol &Kind hinzufgen Add &ChildtreelocalcontrolLKategorie &Hierarchieebene einfgen...Add Category &Level...treelocalcontrolRNeues Kind zu aktuellem Knoten hinzufgen Add new child to selected parenttreelocalcontrolZEinen externen Verweis hinzufgen oder ndern!Add or modify an extrnal web linktreelocalcontrolNInternen Verweis ndern oder hinzufgen#Add or modify an internal node linktreelocalcontrolxOhne gemeinsame Felder kann der Baum nicht expandiert werden#Cannot expand without common fieldstreelocalcontrolKategoriefelderCategory Fieldstreelocalcontrol.&Formatierung entfernenClear For&mattingtreelocalcontrol|Die Formatierung am aktuellen oder selektierten Text entfernen)Clear current or selected text formattingtreelocalcontrol8Klone alle &passenden KnotenClone All &Matched NodestreelocalcontrolRKinder zusammenfassen und Felder vereinen&Collapse descendants by merging fieldstreelocalcontrolTKonvertiere alle passenden Knoten in Klone&Convert all matching nodes into clonestreelocalcontrol>{0} Zweige in Klone konvertiert"Converted {0} branches into clonestreelocalcontrol8Typen aus &Datei kopieren...Copy Types from &File...treelocalcontrolrDen Teilbaum oder den Text in die Zwischenablage kopieren(Copy the branch or text to the clipboardtreelocalcontrolrKonfiguration aus einer anderen TreeLine-Datei bernehmen1Copy the configuration from another TreeLine filetreelocalcontrol&AusschneidenCu&ttreelocalcontrolDen Teilbaum oder Text ausschneiden und in die Zwischenablage legen'Cut the branch or text to the clipboardtreelocalcontrolStandardDefaulttreelocalcontrol>Die ausgewhlten Knoten lschenDelete the selected nodestreelocalcontrolVTrenne alle Klone Knoten im aktuellen Zweig+Detach all cloned nodes in current branchestreelocalcontrol^Fehler: Kann Sicherheitskopie {0} nicht lschen'Error - could not delete backup file {}treelocalcontrolJFehler - Konnte Datei {0} nicht lesenError - could not read file {0}treelocalcontrolRFehler - konnte nicht auf Datei schreibenError - could not write to filetreelocalcontrolPFehler - konnte nicht nach {0} schreibenError - could not write to {}treelocalcontrolfDie Datei in unterschiedlichen Formaten exportieren(Export the file in various other formatstreelocalcontrol`Nach PDF mit aktuellen Druckoptionen exportieren+Export to PDF with current printing optionstreelocalcontrol"Datei gespeichert File savedtreelocalcontrol2&Abflachen nach KategorieFlatten &by Categorytreelocalcontrol(Schriftart &Farbe...Font C&olor...treelocalcontrolErzwinge Aktualisierung alle konditonalen Bedingungen & Mathematischen Feldern3Force update of all conditional types & math fieldstreelocalcontrolBDie ausgewhlten Knoten einrckenIndent the selected nodestreelocalcontrol&Datum einfgen Insert &DatetreelocalcontrolF&Nach ausgewhltem Element einfgenInsert Sibling &AftertreelocalcontrolD&Vor ausgewhltem Element einfgenInsert Sibling &Beforetreelocalcontrol`Kategorieebene oberhalb der Unterknoten einfgen$Insert category nodes above childrentreelocalcontrolBAktuelles Datum als Text einfgenInsert current date as texttreelocalcontrolpEin neues Element nach dem ausgewhlten Element einfgen"Insert new sibling after selectiontreelocalcontrolnEin neues Element vor dem ausgewhlten Element einfgen#Insert new sibling before selectiontreelocalcontrol(&Interner Verweis...Internal &Link...treelocalcontrolGroLargetreelocalcontrol GrerLargertreelocalcontrolAm GrtenLargesttreelocalcontrol.Nach &unten verschieben M&ove Downtreelocalcontrol,Zum Anfang verschieben Move &Firsttreelocalcontrol(Zum Ende verschieben Move &Lasttreelocalcontrol\Die ausgewhlten Knoten nach unten verschiebenMove the selected nodes downtreelocalcontroljDas ausgewhlte Knoten als erstes Unterelement setzen0Move the selected nodes to be the first childrentreelocalcontrollDas ausgewhlte Knoten als letztes Unterelement setzen/Move the selected nodes to be the last childrentreelocalcontrolZDie ausgewhlten Knoten nach oben verschiebenMove the selected nodes uptreelocalcontrolBKeine identischen Knoten gefundenNo identical nodes foundtreelocalcontrolTNeues Fenster fr die gleiche Datei ffnen#Open a new window for the same filetreelocalcontrol,&Drucken einrichten...P&rint Setup...treelocalcontrol$Nu&r Text einfgenPa&ste Plain Texttreelocalcontrol(Kind Knoten einfgen Paste C&hildtreelocalcontrol<Fge geklonten Kind Knoten einPaste Cl&oned ChildtreelocalcontrolZFge geklo&nten Geschwwister Knoten davor einPaste Clo&ned Sibling BeforetreelocalcontrolZFge geklonten Geschwister Knoten &danach einPaste Clone&d Sibling AftertreelocalcontrolBFge Geschwister Knoten d&ahinterPaste Sibling &Aftertreelocalcontrol<Fge Geschwister Knoten &davorPaste Sibling &BeforetreelocalcontroljFge geklonten Kind Knoten von der Zwischenablage ein&Paste a child clone from the clipboardtreelocalcontrolVKind Knoten von der Zwischenablage einfgen%Paste a child node from the clipboardtreelocalcontrolTFge Geschwister Knoten hinter Auswahl einPaste a sibling after selectiontreelocalcontrolNFge Geschwister Knoten vor Auswahl ein Paste a sibling before selectiontreelocalcontrolbFge Geschwister Knoten Klon nach der Auswahl ein%Paste a sibling clone after selectiontreelocalcontrol`Fge Geschwister Knoten Klon vor der Auswahl ein&Paste a sibling clone before selectiontreelocalcontrol`Knoten oder Text von der Zwischenablage einfgen&Paste nodes or text from the clipboardtreelocalcontrolfUnformatierten Text von der Zwischenablage einfgen+Paste non-formatted text from the clipboardtreelocalcontrol(Nach &PDF drucken...Print &to PDF...treelocalcontrol"Druck&vorschau...Print Pre&view...treelocalcontroldBaum basierend auf aktuellen Einstellungen drucken*Print tree output based on current optionstreelocalcontrol"&Eigenschaften...Prop&erties...treelocalcontrolDDie letzte Aktion wiederherstellenRedo the previous undotreelocalcontrolLDen Titel des aktuellen Knotens ndern#Rename the current tree entry titletreelocalcontrol.Tausche Kategorie EbeneS&wap Category Levelstreelocalcontrol&Speichern &unter... Save &As...treelocalcontrolDatei speichern Save Filetreelocalcontrol<nderungen an {0} abspeichern?Save changes to {}?treelocalcontrol.nderungen abspeichern? Save changes?treelocalcontrol0Aktuelle Datei speichernSave the current filetreelocalcontrolVDie Datei unter einem neuen Namen speichernSave the file with a new nametreelocalcontrolFFelder fr die neue Ebene auswhlenSelect fields for new leveltreelocalcontrol.Schriftart Gre setzen Set Font Sizetreelocalcontrol$Knotentyp zuweisen Set Node TypetreelocalcontrolDatei Eigenschaften wie Komprimierung oder Verschlsselung setzen3Set file parameters like compression and encryptiontreelocalcontrolbRnder, Seitengre und andere Druckeinstellungen1Set margins, page size and other printing optionstreelocalcontrolvDie Gre der aktuellen oder selektierten Schriftart setzen(Set size of the current or selected texttreelocalcontrolvDie Farbe der aktuellen oder ausgewhlten Schriftart setzen-Set the color of the current or selected texttreelocalcontroltDie aktuelle oder ausgewhlte Schriftart auf "fett" setzen(Set the current or selected font to boldtreelocalcontrolxDie aktuelle oder ausgewhlte Schriftart auf "kursiv" setzen*Set the current or selected font to italictreelocalcontrolDie aktuelle oder ausgewhlte Schriftart auf "unterstreichen" setzen-Set the current or selected font to underlinetreelocalcontrolTDen Typ fr den ausgewhlten Knoten setzen$Set the node type for selected nodestreelocalcontrolJVorschau der Druckergebnisse anzeigen"Show a preview of printing resultstreelocalcontrol KleinSmalltreelocalcontrol8Rechtschreibprfung fr Text Spell check the tree's text datatreelocalcontrolNTausche Kind und Enkel Kategorie Knoten(Swap child and grandchild category nodestreelocalcontrolPTreeLine - Konfigurationsdatei schreiben"TreeLine - Open Configuration Filetreelocalcontrol4TreeLine - Speichern unterTreeLine - Save Astreelocalcontrol&UnterstreichenU&nderline FonttreelocalcontrolFDie letzte Aktion rckgngig machenUndo the previous actiontreelocalcontrolDie ausgewhlten Knoten "ausrcken" (um eine Ebene nach links verschieben) Unindent the selected nodestreelocalcontrolWarnung - Datei Fehler! berspringe fehlerhafte Kind Verweise in den folgenden Knoten:OWarning - file corruption! Skipped bad child references in the following nodes:treelocalcontrol"ber &TreeLine...&About TreeLine...treemaincontrol6&Grundlegende Verwendung...&Basic Usage...treemaincontrol.Datei ffnen &abbrechen&Cancel File Opentreemaincontrol(&Bedingtes Suchen...&Conditional Find...treemaincontrol8&Datentypen konfigurieren...&Configure Data Types...treemaincontrol0Sicherungskopie &lschen&Delete Backuptreemaincontrol&Suche Text... &Find Text...treemaincontrol8&Umfassende Dokumentation...&Full Documentation...treemaincontrol8Allgemeine &Einstellungen...&General Options...treemaincontrol&Importieren... &Import...treemaincontrol&Neu...&New...treemaincontrol&ffnen...&Open...treemaincontrol&Beenden&QuittreemaincontrolBSicherungskopie &wiederherstellen&Restore Backuptreemaincontrol &Alles auswhlen &Select Alltreemaincontrol&&Beispiel auswhlen&Select Sampletreemaincontrol &Vorlagenauswahl&Select Templatetreemaincontrol&Textfilter...&Text Filter...treemaincontrolSicherheitskopie {} existiert. Eine vorherige Sitzung ist mglicherweise abgestrztEine nicht TreeLine Datei ladenOpen a non-TreeLine filetreemaincontrol2Eine Beispieldatei ffnenOpen a sample filetreemaincontrol.Text in Knoten ersetzen!Replace text strings in node datatreemaincontrolBGesamten Text im Editor auswhlenSelect all text in an editortreemaincontrol@&Tastaturkrzel konfigurieren...Set &Keyboard Shortcuts...treemaincontrolLBenutzereinstellungen fr alle Dateien"Set user preferences for all filestreemaincontrol@Zeige Struktur der Konfiguration Show C&onfiguration Structure...treemaincontrolbZeige nur-lesende Visualisierung der Typ Struktur.Show read-only visualization of type structuretreemaincontrol(Knoten&sortierung...Sor&t Nodes...treemaincontrol,Eine neue Datei ffnenStart a new filetreemaincontrol.TreeLine - Datei ffnenTreeLine - Open Filetreemaincontrol@TreeLine grundlegende VerwendungTreeLine Basic Usagetreemaincontrol(TreeLine Version {0}TreeLine version {0}treemaincontrol2&Nummerierung anpassen...Update &Numbering...treemaincontrol2Die Nummerierung anpassenUpdate node numbering fieldstreemaincontrolDFeldbasierte Bedingungen verwenden$Use field conditions to filter nodestreemaincontrollFeldbasierte Bedingungen verwenden um Knoten zu finden"Use field conditions to find nodestreemaincontrolVWarnung - Socket kann nicht geffnet werden'Warning: Could not create local sockettreemaincontrol*fehlendes Verzeichnismissing directorytreemaincontrol&geschrieben von {0}written by {0}treemaincontrolNeuNewtreenodeHauptprogrammMain treestructurePBedingtes Filter hat {0} Knoten gefunden&Conditional filtering, found {0} nodestreeviewJFiltern nach {0}, {1} Knoten gefunden#Filtering by "{0}", found {1} nodestreeviewNchste: {0} Next: {0}treeview:Nchste: {0} (nicht gefunden)Next: {0} (not found)treeviewSuche nach: Search for:treeviewSuche nach: {0}Search for: {0}treeview@Suche nach: {0} (nicht gefunden)Search for: {0} (not found)treeview$Fenster &schlieen &Close Window treewindow@Teilbaum vollstndig &einklappen&Collapse Full Branch treewindow Da&ten&Data treewindow&Bearbeiten&Edit treewindowBTeilbaum vollstndig &expandieren&Expand Full Branch treewindow &Datei&File treewindow &Hilfe&Help treewindow*&Nachfolgende Auswahl&Next Selection treewindow&Knoten&Node treewindow$&Vorherige Auswahl&Previous Selection treewindow(&Kinder mit anzeigen&Show Child Pane treewindow&Extras&Tools treewindow&Ansicht&View treewindow&Fenster&Window treewindow0Dieses Fenster schlieenClose this window treewindow\Alle Kinder der selektierten Knoten einklappen+Collapse all children of the selected nodes treewindow Datenbearbeitung Data Edit treewindowDatenansicht Data Output treewindow^Alle Kinder der selektierten Knoten expandieren)Expand all children of the selected nodes treewindowFo&rmatFo&rmat treewindowPDie folgende Selektion wieder aktivieren(Go to the next tree selection in history treewindow6Nchste inkrementelle SucheNext Incremental Search treewindow:Vorherige inkrementelle SuchePrevious Incremental Search treewindowPZu der vorherigen Selektion zurckkehren%Return to the previous tree selection treewindow2Zeige &Breadcrumb AnsichtShow &Breadcrumb View treewindow6&berschriftsliste anzeigenShow &Title List treewindow Edit&or anzeigenShow Data &Editor treewindow"&Ansicht anzeigenShow Data &Output treewindowDKinder in der Ausgabe mit anzeigenShow Output &Descendants treewindow`Den Editor in der rechten Fensterhlfte anzeigenShow data editor in right view treewindownDie Daten-Ansicht in der rechten Fensterhlfte anzeigenShow data output in right view treewindowzDie berschriften-Liste in der rechten Fensterhlfte anzeigenShow title list in right view treewindow4Starte inkrementelle SucheStart Incremental Search treewindow"berschriftsliste Title List treewindowTUmschalten zu Breadcrumb Vorfahren Ansicht'Toggle showing breadcrumb ancestor view treewindowfDie Kunde in der Ausgabeansicht eingerckt anzeigen/Toggle showing output view indented descendants treewindowZDie Kinder in der Ausgabeansicht mit anzeigen%Toggle showing right-hand child views treewindowTreeLine-3.2.1/translations/treeline_es.qm000066400000000000000000003051471506556630100206230ustar00rootroot00000000000000zg1DhDm6 x<|e  !eO~%*D01^^0KU7[8nH5 H5 UMVE c s"ExR5y#Ee/%0KH|rr27~;&p**y*^*^*%_*Tچ*J*0_*5+5t+U`:++=f+++MV+:ު+į+aP/5&+5S4P;0&}m$$ fE333MfEBrJTGUM ϋynЄjBsX1d6p7(S1Ah:l9:7a8QAQ Ye#/01P 4FT4M>52{[B"PE%H*aLW*Lef`/`j.v?ot |{y~sB~B6mwbVK/^hKb. ?M M׽Puܷ"݊  N9Q/cD ! h1 e'U _(OY)yN-d9/c52t oOPՇUicf}4Jlemyn6rjs6 uwU\y\}X=+4IeA2HdSa=0V'w9w96*6Dv7gc"zLr 3 f3aP[y&wiMC=$(nٻﶰ.~)}8sFey*y)3|cm /%v_-'@6n6n,6nF;Y \=}>6nIGsLR5._ c g@lx?|§#³:^GI֓֓Do^.ںTAU` x5y!UT .W_<TZ&=b(+$5n6a>>?d @B@{hoFJ%\8q`}@f4gNehTXhѾrc3};N`Rmc]V96G% 5G?c^N J>?lTY(N.$k+%O"D1ϑĮeT+לI_שD/ؙT::KgZkH^ba&SU!m{mNstd0[FѤcyD~n9#UZ#COC#C#&$*,;.C///0?In38L RSS".ZzZG]_Pb#e,fOfȊgl=(r^*Phm^nk ZQITi*1r~|wϥ4Y̿..R e@˃Ψ'H7ie47pI_LE>t[d(s4%YK.&k o&tE(m3K)k/0nd7Ob`8OaCdP[ "R9NSU4Uly]1[hak_kN<nY*nnpjS{}\'n#oRXFN:u/DB" [F*Ǩx˛qO}eQ"u E3X^JfO{ų\M* ='a_"ԟ*Se,0=1cD1cDi9HH@ETFyLC~W1Y|[%{]!bbn#mJ #9Z>cicac "BHnjTz_֤©kM%*)we9=o4.^ #`%%V%%x[ṙ2.<%UWԤ?v޹d߂ߗevv+^Xm ҷ  n \~ \~ ;9K q#- !; 4E 5 :rK F LD! Mgl f+>c kJ 8D  % ωb \eJ b T b* ld x ߡz H U ]  ʵ1 th nb P Z  j ]3 cY} v & . t T  W75 ,_$1 /5F 4b 5r 7*< = IT` Ty UI Wܾ8 _҉)I a cI) c e 8 uo u5 w5 ă_' 5E 1 3~ : I I I IB I Iv Iف I? Cr 8r: 9d` (  ,^ 6"AZ 5V ' 6T ^ I > 5 t ˈ* ĽN:; ;: Gc$H : : JB ; ;Q 5z e3 & > s . D t X KE )M! -8 .2,# /. 2  55r 93) @(e Al KsGs K( L.< L98 W% X [tf pI3} rW x( c x( {u[; :3.A % s  H  ! > Z: i[S >$ DL (t ]o+ M g D) fq B ~7+ ш t ٷ ߺ KGa| ~9 \E% iG ^$M y~c : v  [ EN^ E= +Cu P % #= Q lg d '{ (EG * 2l$ 7"- 8Ǒq ;y: =! @|5 @6 V>Y dMi g#3 n/ pkx t*# t&J tu v" a {B =L1 D eN hO M^ TC R ^ , C- 4 em m)v үW v bnb DA U( / Yi L \< -| F c ' .[ 0uOz 0 7y9 CG G9.i H3m Kz9 KI^ M Nh ]`^g} _ t dT i5 i$ i$V zG J 2  ݃ |C =2f c*j ˜SR D T# sO ~t >B s :fz eIc"T`6ssV(t'({Q-K/+i0/aS0>a9O= %BEj;H;}L`g(L L|L^_V8 YiZrhji?kjlfcCp#Gqtt/C}~DBw^A4B-rtZfOb xt2:k~?-`Eoԕ Ձ]iYe09hy tipxVC#y`USw;>`h Kc wR(J68 qwE<@-*HNICMUZ8n?[Ke3em3PiFW@rs$ Xww|*\}$7^?y,A 2ӝZԲ9 o]#tg2IkmuHn#HkFs*o4u+)$&|ɟ)u~!]>Yxo;+o_dLp36fwil&Cancelar&Cancelcolorset&OK&OKcolorsetColor de Tema Color Themecolorset&Aadir &Nueva Regla &Add New Rule conditional&Cancelar&Cancel conditional&Cerrar&Close conditional&Borrar&Delete conditional &Terminar filtro &End Filter conditional&Filtro&Filter conditionalCar&gar&Load conditional&OK&OK conditional&Eliminar Regla &Remove Rule conditionalGuar&dar&Save conditional FalsoFalse conditional"Buscar &Siguiente Find &Next conditional B&uscar AnteriorFind &Previous conditionalNombre:Name: conditionalTCoincidencias condicionales no encontradas!No conditional matches were found conditionalTipo de nodo Node Type conditionalRegla {0}Rule {0} conditional Reglas Guardadas Saved Rules conditionalVerdaderoTrue conditional"[Todos los tipos] [All Types] conditionalyand conditionalcontienecontains conditionaltermina con ends with conditionaloor conditionalcomienza con starts with conditional&Aplicar&Apply configdialog&Cancelar&Cancel configdialogTipo de &Datos &Data Type configdialog&Eliminar tipo &Delete Type configdialog,&Derivado del original&Derive from original configdialog&Ecuacin &Equation configdialog0Configuracin de &Campos &Field Config configdialogTip&o de Campo &Field Type configdialog"&Ocultar Avanzado&Hide Advanced configdialogMover Aba&jo &Move Down configdialog&Nuevo Campo... &New Field... configdialog&Nuevo Tipo... &New Type... configdialog&OK&OK configdialogP&refijo&Prefix configdialog&Reiniciar&Reset configdialog&Resultado Tipo &Result Type configdialog"&Seleccionar Todo &Select All configdialog"&Mostrar Avanzado&Show Advanced configdialog.C&riterio de Ordenacin&Sort Criteria configdialog$&Formato de Ttulo &Title Format configdialogHAgregar lnea en &blanco entre nodosAdd &blank lines between nodes configdialogAadir Campo Add Field configdialogAadir tipoAdd Type configdialog<Aadir o Quitar Datos de TiposAdd or Remove Data Types configdialog2Agregar &vietas al textoAdd text bullet&s configdialog^Permitir &HTML con formato de texto enriquecidoAllow &HTML rich text in format configdialog,Operadores AritmticosArithmetic Operators configdialog"Tipos AutomticosAutomatic Types configdialog6Lista de &Campos DisponibleAvailable &Field List configdialog&Campos &DisponiblesAvailable &Fields configdialog$Resultado BooleanoBoolean Result configdialogNo se puede eliminar un tipo de datos que est siendo usado por algn nodo+Cannot delete data type being used by nodes configdialogCambiar &Icono Change &Icon configdialog"Recuento de Hijos Child Count configdialogReferencia HijaChild Reference configdialog2Lmites de los Tipos HijoChild Type Limits configdialog"Borrar &Seleccin Clear &Select configdialogCo&piar Tipo... Co&py Type... configdialogdCombinacin && &separador lista de hijos de Salida+Combination && Child List Output &Separator configdialog.Operadores ComparativosComparison Operators configdialog2Configurar Tipos de DatosConfigure Data Types configdialogCopiar Tipo Copy Type configdialog4Crear Tipos Co&ndicionalesCreate Co&nditional Types configdialog$Resultado de Fecha Date Result configdialogH&Valor por Defecto para Nuevos NodosDefault &Value for New Nodes configdialog,Tipo Hi&jo por DefectoDefault Child &Type configdialog Definir EcuacinDefine Equation configdialogNDefinir el Campo de Ecuacin MatemticaDefine Math Field Equation configdialog&Borrar Campo Dele&te Field configdialog6Derivado del Tipo &GenricoDerived from &Generic Type configdialogDescripcin Description configdialogDireccin Direction configdialog"Altura del editor Editor Height configdialogJIntroduzca el nombre del nuevo campo:Enter new field name: configdialogBEstablecer nombre del nuevo tipo:Enter new type name: configdialog*Erron en ecuacin: {}Equation error: {} configdialogzError - referencia circular en ecuaciones de campo matemtico2Error - circular reference in math field equations configdialog.Evaluar etiquetas &HTMLEvaluate &HTML tags configdialogTexto Adicional Extra Text configdialog Cam&poF&ield configdialog &Lista de Campos F&ield List configdialog CampoField configdialog Lista de &Campos Field &List configdialog(Referencias de CampoField References configdialogHReferencia de informacin de archivoFile Info Reference configdialog$Cam&biar DireccinFlip &Direction configdialog(Ayuda sobre &Formato Format &Help configdialog IconoIcon configdialog&Ecuacin matemtica Math Equation configdialog4Modificar &Lista de CamposModify &Field List configdialog<Modificar Tipos Co&ndicionalesModify Co&nditional Types configdialogMover A&rribaMove &Up configdialogMover Aba&jo Move Do&wn configdialogMo&ver ArribaMove U&p configdialog NombreName configdialogNadaNone configdialog4Nmero de lneas de te&xtoNum&ber of text lines configdialog$Resultado Numrico Number Result configdialog"Tipo de O&peradorO&perator Type configdialog &Salida de DatosO&utput configdialog(Lista de Oper&adoresOper&ator List configdialogOperaciones Operations configdialog6Otras Referencias de CamposOther Field References configdialog$&Formato de SalidaOut&put Format configdialog$Formato de Sa&lidaOutpu&t Format configdialogSalida HTML Output HTML configdialog$Opciones de SalidaOutput Options configdialog Referencia PadreParent Reference configdialog&Tipo de Refere&nciaRefere&nce Type configdialog(Referencia de &NivelReference &Level configdialog&Referencia de &TipoReference &Type configdialog(Niv&el de ReferenciaReference Le&vel configdialog&Renombrar Cam&po...Rena&me Field... configdialog$Renom&brar Tipo...Rena&me Type... configdialogRenombrar Campo Rename Field configdialogRenombrar tipo Rename Type configdialog$Renombrar de {} a:Rename from {} to: configdialogReferencia RazRoot Reference configdialog(Seleccionar &Ninguno Select &None configdialogAutoreferenciaSelf Reference configdialogJEstablecer el Icono del Tipo de DatosSet Data Type Icon configdialogBConfigurar Tipos CondicionalmenteSet Types Conditionally configdialog$Ord&enar Claves... Sort &Keys... configdialog,Clave de ClasificacinSort Key configdialog(Ordenar Campos ClaveSort Key Fields configdialogSufi&joSuffi&x configdialogLista de &Tipos T&ype List configdialog&Operadores de TextoText Operators configdialog Texto Resultante Text Result configdialogbLos siguientes caracteres no estn permitidos: {},The following characters are not allowed: {} configdialog<El nombre no puede estar vacoThe name cannot be empty configdialogHEl nombre no puede contener espaciosThe name cannot contain spaces configdialogJEl nombre no puede comenzar con "xml" The name cannot start with "xml" configdialogJEl nombre debe comenzar con una letra!The name must start with a letter configdialog0El nombre ya est en usoThe name was already used configdialog&Resultado de Tiempo Time Result configdialog Configurar &Tipo Typ&e Config configdialogTipoType configdialog@Mostrar datos de campo en tab&laUse a table for field &data configdialog:[Todos los Tipos Disponibles][All Types Available] configdialog [Nada][None] configdialogvalor absolutoabsolute value configdialog sumaradd configdialogarcocoseno arc cosine configdialogarcosenoarc sine configdialogarcotangente arc tangent configdialogpromedioaverage configdialog(logaritmo en base 10base-10 logarithm configdialog concatenar textoconcatenate text configdialog8convertir texto a minsculasconvert text to lower case configdialog8convertir texto a maysculasconvert text to upper case configdialog coseno de radincosine of radians configdialog"grados a radianesdegrees to radians configdialogdividirdivide configdialogigual aequal to configdialogfactorial factorial configdialogpunto flotantefloating point configdialog*divisin por redondeo floor divide configdialogadelanteforward configdialogAdelantefwd configdialogmayor que greater than configdialog"mayor o igual quegreater than or equal to configdialogentero mayorhigher integer configdialogen primer argumento, reemplazar segundo argumento con tercer argumento(in 1st arg, replace 2nd arg with 3rd arg configdialoghunir texto usando como primer argumento un separador$join text using 1st arg as separator configdialogmenor que less than configdialog"menor o igual queless than or equal to configdialoglgico y logical and configdialoglgico o logical or configdialogentero menor lower integer configdialog mximomaximum configdialog mnimominimum configdialog mdulomodulus configdialogmultiplicarmultiply configdialog6constante logaritmo naturalnatural log constant configdialog"logaritmo naturalnatural logarithm configdialogdistinto a not equal to configdialog*nmero pi (constante) pi constant configdialogpotenciapower configdialog"radianes a gradosradians to degrees configdialog Atrsrev configdialog atrsreverse configdialog:redondear a nmero de dgitosround to num digits configdialogseno de radinsine of radians configdialograz cuadrada square root configdialog restarsubtract configdialogsuma de tems sum of items configdialog$Tangente de Radintangent of radians configdialogverdadero si el argumentdo del primer texto contiene un segundo argumento%true if 1st text arg contains 2nd arg configdialogverdadero si el argumentdo del primer texto termina con un segundo argumento&true if 1st text arg ends with 2nd arg configdialogverdadero si el argumentdo del primer texto comienza con un segundo argumento(true if 1st text arg starts with 2nd arg configdialogNvalor verdadero, condicin, valor falso"true value, condition, false value configdialogentero truncadotruncated integer configdialog(&Seleccionar Archivo&Browse for File dataeditors&Cancelar&Cancel dataeditors&Ir al Destino &Go to Target dataeditors&OK&OK dataeditors&Abrir Enlace &Open Link dataeditors&Abrir Imagen &Open Picture dataeditorsJ(Clicar objeto a enlazar en el rbol)(Click link target in tree) dataeditorsAbsolutaAbsolute dataeditorsDireccinAddress dataeditorsBorrar En&lace Clear &Link dataeditorsMostrar Nombre Display Name dataeditorsEnlace Externo External Link dataeditors.Tipo de ruta de archivoFile Path Type dataeditorsEnlace Interno Internal Link dataeditorsAbrir &Carpeta Open &Folder dataeditors Enlace de Imagen Picture Link dataeditorsRelativaRelative dataeditorsEsquemaScheme dataeditors"Establecer A&hora Set to &Now dataeditorsFecha de &Hoy Today's &Date dataeditorsFTreeLine - Enlace a archivo externoTreeLine - External Link File dataeditors8TreeLine - Archivo de ImagenTreeLine - Picture File dataeditors enlacelink dataeditors&Columnas&ColumnsexportsTabla &de descendientes delimitada por comas (CSV) (nmero de niveles);&Comma delimited (CSV) table of descendants (level numbers)exports&Todo el rbol &Entire treeexports &HTML&HTMLexports4Formato &HTML de favoritos&HTML format bookmarksexports6&Incluir noddos principales&Include root nodesexports(&ODF Texto (esquema) &ODF Outlineexports4&Antiguos TreeLine (2.0.x)&Old TreeLine (2.0.x)exports.Abrir s&olo nodos hijos&Only open node childrenexports&Pgina HTML &Simple&Single HTML pageexportsB&Texto con tabulacin por ttulos&Tabbed title textexports &Texto&Textexports$&Subrbol TreeLine&TreeLine SubtreeexportsL&Salida sin formato para todo el texto&Unformatted output of all textexports4Formato &XBEL de favoritos&XBEL format bookmarksexports&XML (genrico)&XML (generic)exports&Favoritos Book&marksexportsFavoritos BookmarksexportsXSeleccionar subtipo de formato para exportarChoose export format subtypeexportsRSeleccionar tipo de formato para exportarChoose export format typeexportsDSeleccionar opciones para exportarChoose export optionsexportspT&abla de hijos delimitada por comas (CSV) (nivel nico)7Comma &delimited (CSV) table of children (single level)exportsError: No se puede vincular al archivo TreeLine no guardado. Guarde el archivo y vuelva a intentarlo.FError - cannot link to unsaved TreeLine file. Save the file and retry.exportsError - Exportar archivos de plantilla no encontrados. Verifique la instalacin de su TreeLine.JError - export template files not found. Check your TreeLine installation.exports Exportar Archivo File ExportexportsLIncluir im&presin de encabezado y pieInclude &print header && footerexportsVista de rbol en tiempo real, vinculada al archivo TreeLine (para servidor web)8Live tree view, linked to TreeLine file (for web server)exportsVista de rbol en tiempo real, archivo nico (datos incrustados)+Live tree view, single file (embedded data)exports>Mltiples tablas de datos &HTMLMultiple HTML &data tablesexports^&Multiples pginas HTML con panel de navegacin)Multiple HTML &pages with navigation paneexportsPDebe seleccionar nodos antes de exportar!Must select nodes prior to exportexports@Nive&les del Panel de NavegacinNavigation pane &levelsexportsOtras Opciones Other Optionsexports PadreParentexports(&Ramas SeleccionadasSelected &branchesexports(&Nodos SeleccionadosSelected &nodesexportsV&Pgina HTML simple con panel de navegacin&Single &HTML page with navigation paneexportsTa&bla delimitada por tabulaciones segn nodos hijos (nivel nico)0Tab &delimited table of children (&single level)exportsTree&Line Tree&Lineexports@TreeLine - Exportar XML GenricoTreeLine - Export Generic XMLexports0TreeLine - Exportar HTMLTreeLine - Export HTMLexportsDTreeLine - Exportar Favoritos HTML TreeLine - Export HTML Bookmarksexports$Exportar Texto ODFTreeLine - Export ODF Textexports>TreeLine - Exportar Texto PlanoTreeLine - Export Plain TextexportsFTreeLine - Exportar Tablas de TextoTreeLine - Export Text TablesexportsJTreeLine - Exportar Textos de TtulosTreeLine - Export Text TitlesexportsJTreeLine - Exportar Subrbol TreeLine"TreeLine - Export TreeLine SubtreeexportsDTreeLine - Exportar Favoritos XBEL TreeLine - Export XBEL BookmarksexportsAdvertencia: no hay una ruta relativa entre "{0}" y "{1}". Continuar con la ruta absoluta?LWarning - no relative path from "{0}" to "{1}". Continue with absolute path?exportsQu exportarWhat to Exportexports"." Carcter .."." Character .. fieldformat"/" Carcter //"/" Character // fieldformat(0 1 Repeticiones ?0 Or 1 Repetitions ? fieldformat,0 o ms repeticiones *0 Or More Repetitions * fieldformat,1 o ms repeticiones +1 Or More Repetitions + fieldformatAM/PM %pAM/PM %p fieldformat(Cualquier Carcter .Any Character . fieldformatAutoEleccin AutoChoice fieldformatAutoCombinacinAutoCombination fieldformatBooleanoBoolean fieldformatMaysculas ACapital Letter A fieldformat<Nmeros Romanos (maysculas) ICapital Roman Numeral I fieldformatEleccinChoice fieldformatCombinacin Combination fieldformat"Separador Coma \,Comma Separator \, fieldformat FechaDate fieldformatFecha y horaDateTime fieldformat.Da (1 2 dgitos) %-dDay (1 or 2 digits) %-d fieldformat$Da (2 dgitos) %dDay (2 digits) %d fieldformat2Da del ao (1 a 366) %-jDay of year (1 to 366) %-j fieldformatComa Decimal ,Decimal Comma , fieldformatPunto Decimal .Decimal Point . fieldformat&Cuenta DescendienteDescendantCount fieldformatDDgito o Espacio (externo) <space>!Digit or Space (external)  fieldformat$Separador Punto \.Dot Separator \. fieldformat"Final del Texto $ End of Text $ fieldformat4Escape carcter especial \Escape a Special Character \ fieldformatEjemplo 1/2/3/4Example 1/2/3/4 fieldformat.Exponente (mayscula) EExponent (capital) E fieldformat.Exponente (minscula) eExponent (small) e fieldformatEnlace Externo ExternalLink fieldformat<Hora (0-23, 1 2 dgitos) %-HHour (0-23, 1 or 2 digits) %-H fieldformat4Hora (00-23, 2 dgitos) %HHour (00-23, 2 digits) %H fieldformat4Hora (01-12, 2 dgitos) %IHour (01-12, 2 digits) %I fieldformat<Hora (1-12, 1 2 dgitos) %-IHour (1-12, 1 or 2 digits) %-I fieldformatTexto HtmlHtmlText fieldformatEnlaceInterno InternalLink fieldformat(Separador de nivel /Level Separator / fieldformat Minsculas [a-z]Lower Case Letters [a-z] fieldformatMatemticasMath fieldformat8Microsegundos (6 dgitos) %fMicroseconds (6 digits) %f fieldformat6Minutos (1 2 dgitos) %-MMinute (1 or 2 digits) %-M fieldformat,Minutos (2 dgitos) %MMinute (2 digits) %M fieldformat.Mes (1 o 2 dgitos) %-mMonth (1 or 2 digits) %-m fieldformat$Mes (2 dgitos) %mMonth (2 digits) %m fieldformat$Mes (abreviado) %bMonth Abbreviation %b fieldformat0Mes (nombre completo) %B Month Name %B fieldformat,No es un nmero [^0-9]Not a Number [^0-9] fieldformat AhoraNow fieldformat NmeroNumber fieldformatNmero 1Number 1 fieldformatNumeracin Numbering fieldformat$Texto de una lnea OneLineText fieldformat"Dgito Opcional #Optional Digit # fieldformat Signo Opcional -Optional Sign - fieldformatO |Or | fieldformatHEjemplo de esquema I../A../1../a)/i)!Outline Example I../A../1../a)/i) fieldformat ImagenPicture fieldformat"Expresin regularRegularExpression fieldformat$Dgito Requerido 0Required Digit 0 fieldformat"Signo Requerido +Required Sign + fieldformat8Segundos (1 2 dgitos) %-SSecond (1 or 2 digits) %-S fieldformat.Segundos (2 dgitos) %SSecond (2 digits) %S fieldformat4Ejemplo de seccin 1.1.1.1Section Example 1.1.1.1 fieldformat,Separador de seccin .Section Separator . fieldformatSeparador / Separator / fieldformat2Conjunto de Nmeros [0-9]Set of Numbers [0-9] fieldformatMinsculas aSmall Letter a fieldformat<Nmeros romanos (minsculas) iSmall Roman Numeral i fieldformatFSeparador Espacio (interno) <space>"Space Separator (internal)  fieldformatTexto espaciado SpacedText fieldformatV/FT/F fieldformat TextoText fieldformatHoraTime fieldformat Maysculas [A-Z]Upper Case Letters [A-Z] fieldformat&Semana (0 a 53) %-UWeek Number (0 to 53) %-U fieldformat@Da de la semana (abreviado) %aWeekday Abbreviation %a fieldformat&Da de la semana %AWeekday Name %A fieldformatS/NY/N fieldformat$Ao (2 dgitos) %yYear (2 digits) %y fieldformat$Ao (4 dgitos) %YYear (4 digits) %Y fieldformatverdadero/falso true/false fieldformat s/noyes/no fieldformat falsofalse genbooleannono genbooleanverdaderotrue genbooleansyes genboolean$Todos los Archivos All Files globalref6Todos los Archivos TreeLineAll TreeLine Files globalrefFArchivos CSV (Delimitado por Comas)CSV (Comma Delimited) Files globalrefArchivos HTML HTML Files globalref*Archivos de Texto ODFODF Text Files globalref4Archivos TreeLine AntiguosOld TreeLine Files globalrefArchivos PDF PDF Files globalref"Archivos de Texto Text Files globalref"Archivos TreeLineTreeLine Files globalref<Archivos TreeLine - ComprimidoTreeLine Files - Compressed globalref<Archivos TreeLine - EncriptadoTreeLine Files - Encrypted globalref&Archivos de Treepad Treepad Files globalrefArchivos XML XML Files globalref Buscar:  Find: helpview&Volver&Backhelpview&Siguiente&Forwardhelpview&Inicio&Homehelpview"&Buscar Siguiente Find &Nexthelpview Buscar &AnteriorFind &Previoushelpview:Cadena de texto no encontradaText string not foundhelpviewHerramientasToolshelpview"{0}" no es un archivo vlido TreeLine. Usar filtro de importacin de archivo?:"{0}" is not a valid TreeLine file. Use an import filter?importsRXML &genrico (No es un archivo TreeLine) &Generic XML (non-TreeLine file)importsB&HTML favoritos (Formato Mozilla) &HTML bookmarks (Mozilla Format)importsl&Sangrado de texto por tabulaciones, un nodo por lnea%&Tab indented text, one node per lineimports@Favoritos en &XML (Formato XBEL)&XML bookmarks (XBEL format)importsFAVORITOBOOKMARKimports@Formato CSV.errneo en Lnea {0}Bad CSV format on Line {0}importsFavoritos Bookmarksimports:Escoger Mtodo de ImportacinChoose Import MethodimportsT&exto delimitado por comas (CSV) tabla de texto con nivel de columna y fila de encabezadoACo&mma delimited (CSV) text table with level column && header rowimports|Texto &delimitado por comas (CSV) tabla con fila de encabezado1Comma delimited (CSV) text table &with header rowimportsDError-no se puede leer archivo {0}Error - could not read file {0}importsBError - formato incorrecto en {0}Error - improper format in {0}importsCARPETAFOLDERimports Importar Archivo Import Fileimports"Archivo no Vlido Invalid FileimportsRNmero de nivel no vlido en la lnea {0} Invalid level number on line {0}imports:Estructura de nivel no vlidaInvalid level structureimports EnlaceLinkimportsPArchivo Antiguo de Tree&Line (1.x o 2.x)Old Tree&Line File (1.x or 2.x)imports(Open &Document (ODF)Open &Document (ODF) outlineimportsOtroOtherimportsrTexto &plano en prrafos (delimitado por lnea en blanco)-Plain text ¶graphs (blank line delimited)importsText&o plano, un &nodo por lnea (delimitado por retorno de carro -CR-)-Plain text, one &node per line (CR delimited)importsSEPARADOR SEPARATORimports TABLATABLEimportsTabl&a de texto delimitada por tabulaciones con fila de encabezado)Tab delimited text table with header &rowimports TextoTextimportsFDemasiadas entradas en la Lnea {0}Too many entries on Line {0}imports6TreeLine - Importar archivoTreeLine - Import FileimportsX&Archivo Treepad (nicamente nodos de texto)Treepad &file (text nodes only)importsvLas referencias secundarias deben combinarse en una funcin/Child references must be combined in a functionmatheval:Caracteres "{}" no permitidosIllegal "{}" charactersmatheval8Funcin ilegal presente: {0}Illegal function present: {0}mathevalVTipo de objeto u operador no permitido: {0}$Illegal object type or operator: {0}matheval<Sintaxis ilegar en la ecuacinIllegal syntax in equationmathevalA&plicar&Apply miscdialogs&Cancelar&Cancel miscdialogs&Cerrar&Close miscdialogsC&errar Filtro &End Filter miscdialogsrbol compl&eto &Entire tree miscdialogs&Filtro&Filter miscdialogs"&Buscar Siguiente &Find Next miscdialogs&Adelante&Forward miscdialogs"&Ignorar y omitir&Ignore and skip miscdialogs&Contiene &Key words miscdialogsTipo de &Nodo &Node Type miscdialogs&OK&OK miscdialogs>Nombres de Campos &Predefinidos&Predefined Key Fields miscdialogs$Exp&resin regular&Regular expression miscdialogs&Reemplazar&Replace miscdialogs^&Reiniciar nmeros para los siguientes hermanos"&Restart numbers for next siblings miscdialogs>&Restaurar Valores por &Defecto&Restore Defaults miscdialogs At&rs&Reverse miscdialogs&Buscar texto &Search Text miscdialogs&&Seleccin de Hijos&Selection's children miscdialogs Slo en &ttulos &Titles only miscdialogs.Barras de herramien&tas &Toolbars miscdialogsbConsiderar los espacios en blanco como ceros (&0)&Treat blank fields as zeros miscdialogs^&Usar la fuente predeterminada de la aplicacin&Use app default font miscdialogs$&Comprimir Archivo&Use file compression miscdialogsH&Usar fuente por defecto del sistema&Use system default font miscdialogs--Separador-- --Separator-- miscdialogsSe ha producido un error grave. TreeLine podra estar en un estado inestable. Se recomienda guardar cualquier cambio de archivo con otro nombre de archivo y reiniciar TreeLine. La informacin de depuracin que se muestra a continuacin se puede copiar y enviar por correo electrnico a doug101@bellz.org junto con una explicacin de las circunstancias del error. A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances.  miscdialogs*Comandos Dis&poniblesA&vailable Commands miscdialogsCo&ntiene Any &match miscdialogsFFuente por defecto de la aplicacinApp Default Font miscdialogsBorrar Cla&ve Clear &Key miscdialogs(Personalizar FuentesCustomize Fonts miscdialogsDPersonalizar Barra de HerramientasCustomize Toolbars miscdialogs DatosData miscdialogsMen de datos Data Menu miscdialogs:Predeterminado - Texto SimpleDefault - Single Line Text miscdialogs EditarEdit miscdialogsMen Edicin Edit Menu miscdialogs"Fuente del EditorEditor View Font miscdialogsBContrasea del Archivo EncriptadoEncrypted File Password miscdialogsFError - Expresin regular no vlida"Error - invalid regular expression miscdialogs2Error - reemplazo fallidoError - replacement failed miscdialogsFrase co&mpleta F&ull phrase miscdialogs CamposFields miscdialogsArchivoFile miscdialogsMen de Archivo File Menu miscdialogs,Propiedades de ArchivoFile Properties miscdialogs4Almacenamiento de Archivos File Storage miscdialogs FiltroFilter miscdialogs BuscarFind miscdialogs"Buscar &Siguiente Find &Next miscdialogs Buscar &AnteriorFind &Previous miscdialogs&Buscar y reemplazarFind and Replace miscdialogsFormatoFormat miscdialogsMen Formato Format Menu miscdialogsEn to&do Full &data miscdialogsCoinci&de Full &words miscdialogsLManejar nodos sin Campos de Numeracin'Handling Nodes without Numbering Fields miscdialogs AyudaHelp miscdialogsMen Ayuda Help Menu miscdialogsCmo Buscar How to Search miscdialogs>Incluir nodos de nivel superiorInclude top-level nodes miscdialogsTexto E&xactoKey full &words miscdialogs0Clave {0} ya est en usoKey {0} is already used miscdialogs"Atajos de TecladoKeyboard Shortcuts miscdialogsRCdigo de idioma o diccionario (opcional)&Language code or dictionary (optional) miscdialogsIconos Grandes Large Icons miscdialogs$Campos Matemticos Math Fields miscdialogsMover Aba&jo Move &Down miscdialogsMover &ArribaMove &Up miscdialogsCampos de N&odo N&ode Fields miscdialogsNo.menuNo menu miscdialogsxNo se encontraron campos de numeracin en los tipos de datos,No numbering fields were found in data types miscdialogsNodoNode miscdialogs"&Ttulos de Nodos Node &Titles miscdialogsMen de Nodo Node Menu miscdialogs Fuente de SalidaOutput View Font miscdialogs$Expresin re&gularRe&gular expression miscdialogs>Escriba de nuevo la contrasea:Re-Type Password: miscdialogsFLa contrasea reescrita no coincideRe-typed password did not match miscdialogsTRecordar la contrasea durante esta sesin%Remember password during this session miscdialogs Reemplaz&ar Todo Replace &All miscdialogs<Reemplazadas {0} coincidenciasReplaced {0} matches miscdialogs"Reemplazar &TextoReplacement &Text miscdialogs Reserva &nmerosReserve &numbers miscdialogsNodo Principal Root Node miscdialogsDBuscar cadena "{0}". No encontradaSearch string "{0}" not found miscdialogsLBsqueda del texto "{0}" no encontradoSearch text "{0}" not found miscdialogs(Ramas &SeleccionadasSelected &branches miscdialogs.Her&manos seleccionadosSelection's &siblings miscdialogs(&Hijos seleccionadosSelection's childre&n miscdialogsIconos Pequeos Small Icons miscdialogs*Direccin de OrdenadoSort Direction miscdialogs$Mtodo de ordenado Sort Method miscdialogsOrdenar Nodos Sort Nodes miscdialogs:Comprobacin de la ortografa Spell Check miscdialogsJComandos de la &barra de herramientasTool&bar Commands miscdialogs:Tamao Barra de Herramienta&s Toolbar &Size miscdialogsDCantidad de barras de herramientasToolbar Quantity miscdialogsHerramientasTools miscdialogs(Men de Herramientas Tools Menu miscdialogs Fuente del rbolTree View Font miscdialogs,TreeLine - Error GraveTreeLine - Serious Error miscdialogs&Numeracin TreeLineTreeLine Numbering miscdialogsBEscriba la Contrasea para "{0}":Type Password for "{0}": miscdialogs,Escriba la Contrasea:Type Password: miscdialogs:Actualizar Numeracin de NodoUpdate Node Numbering miscdialogs$&Encriptar ArchivoUse file &encryption miscdialogsVerView miscdialogsMen Ver View Menu miscdialogsDnde BuscarWhat to Search miscdialogsQu ordenar What to Sort miscdialogsQu ActualizarWhat to Update miscdialogsVentanaWindow miscdialogsMen Ventana Window Menu miscdialogsVNo se permiten contraseas de longitud cero'Zero-length passwords are not permitted miscdialogs$[Todos los campos] [All Fields] miscdialogs"[Todos los tipos] [All Types] miscdialogs NombreName nodeformatActivar editores de datos cuando el puntero del ratn est encima$Activate data editors on mouse hoveroptiondefaultsApariencia Appearanceoptiondefaults(Grabacin automtica Auto SaveoptiondefaultsZAbrir automticamente el ltimo archivo usado!Automatically open last file usedoptiondefaultsCorreccin de sangrado de hijos (en unidades de altura de fuente) +Child indent offset (in font height units) optiondefaults:Clicar en nodo para renombrarClick node to renameoptiondefaults8Formatos del editor de datosData Editor Formatsoptiondefaults FechasDatesoptiondefaults6Funcionalidades disponiblesFeatures Availableoptiondefaults.Primer da de la semanaFirst day of weekoptiondefaultsViernesFridayoptiondefaultsbSangrado (mejor impresin) Archivos TreeLine JSON)Indent (pretty print) TreeLine JSON filesoptiondefaultsXMinimiza aplicacin a la bandeja del sistema#Minimize application to system trayoptiondefaultslMinutos entre respaldos (seleccione 0 para desactivar)+Minutes between saves (set to 0 to disable)optiondefaults LunesMondayoptiondefaultshCantidad de archivos recientes en el men de archivo(Number of recent files in the file menuoptiondefaults:Nmero de niveles de deshacerNumber of undo levelsoptiondefaultsFAbrir archivos en una nueva ventanaOpen files in new windowsoptiondefaults$Archivos recientes Recent FilesoptiondefaultsEliminar archivos inaccesibles en la vista de archivos recientes'Remove inaccessible recent file entriesoptiondefaults\Renombrar los nodos nuevos cuando sean creadosRename new nodes when createdoptiondefaultsZRestaurar la geometra de la ventana anterior Restore previous window geometryoptiondefaultsrRestaurar estados de vista en rbol de archivos recientes(Restore tree view states of recent filesoptiondefaults SbadoSaturdayoptiondefaults6Mostrar panel de navegacinShow breadcrumb ancestor viewoptiondefaultsPMotrar paneles hijos en la vista derecha#Show child pane in right hand viewsoptiondefaultsFMostrar hijos en la vista de salidaShow descendants in output viewoptiondefaultsFMostrar iconos en la vista de rbolShow icons in the tree viewoptiondefaultstMostrar campos matemticos en la vista de Edicin de Datos&Show math fields in the Data Edit viewoptiondefaultsxMostrar campos de numeracin en la vista de Edicin de Datos+Show numbering fields in the Data Edit viewoptiondefaults&Condicin de InicioStartup ConditionoptiondefaultsDomingoSundayoptiondefaults JuevesThursdayoptiondefaults HorasTimesoptiondefaultslDisponible la opcin de pulsar y arrastrar en el rbolTree drag && drop availableoptiondefaults MartesTuesdayoptiondefaultsLMemoria usada por la opcin "deshacer" Undo MemoryoptiondefaultsMircoles Wednesdayoptiondefaults&Cancelar&Canceloptions&Aceptar&OKoptions^Elija la ubicacin del archivo de configuracin"Choose configuration file locationoptionsPCarpeta del programa (para uso portable)$Program directory (for portable use)optionsZDirectorio de inicio de usuario (recomendado)#User's home directory (recommended)options@Error inicializando la impresoraError initializing printer printdata2TreeLine - Exportar a PDFTreeLine - Export PDF printdataAdvertencia: configuracin de margen no compatible en la impresora actual. Guardar los ajustes?JWarning: Margin settings unsupported on current printer. Save adjustments? printdataAdvertencia: configuracin de tamao de pgina y margen no admitida en la impresora actual. Guardar los ajustes de pgina?]Warning: Page size and margin settings unsupported on current printer. Save page adjustments? printdataAdvertencia: configuracin de tamao de pgina no admitida en la impresora actual. Guardar ajustes?KWarning: Page size setting unsupported on current printer. Save adjustment? printdataA&bajo:&Bottom: printdialogs&Cancelar&Cancel printdialogsH&Dibujar lneas para los nodos hijos&Draw lines to children printdialogs&rbol completo &Entire tree printdialogs&Fuente&Font printdialogs(Seleccin de &Fuente&Font Selection printdialogs&Opciones &Generales&General Options printdialogs*Encabezado I&zquierdo &Header Left printdialogs"&Encabezado y pie&Header/Footer printdialogs*Incluir el nodo rai&z&Include root node printdialogsT&Mantener el primer nodo hijo con el padre&Keep first child with parent printdialogsIz&quierda:&Left: printdialogs&&Nmero de columnas&Number of columns printdialogs&OK&OK printdialogs&Prefijo&Prefix printdialogs&Imprimir... &Print... printdialogsDerec&ha:&Right: printdialogs&Sufijo&Suffix printdialogsA&rriba:&Top: printdialogs&Unidades&Units printdialogs&Usar la misma que haya configurada en "Salida de Datos" de TreeLine&Use TreeLine output view font printdialogsA&nchura:&Width: printdialogs"A3 (279 x 420 mm)A3 (279 x 420 mm) printdialogs"A4 (210 x 297 mm)A4 (210 x 297 mm) printdialogs"A5 (148 x 210 mm)A5 (148 x 210 mm) printdialogs>AaBbCcDdEeFfGg...TtUuVvWvXxYyZzAaBbCcDdEeFfGg...TtUuVvWvXxYyZz printdialogs Centmetros (cm)Centimeters (cm) printdialogsColumnasColumns printdialogs(Tamao Personalizado Custom Size printdialogs*Fuente predeterminada Default Font printdialogsXError: Tamao de pgina o mrgenes invlidos(Error: Page size or margins are invalid printdialogsTexto adicional Extra Text printdialogs&Pginas enfrentadas Facing Pages printdialogsCaractersticasFeatures printdialogsCampo&sFiel&ds printdialogs"For&mato de Campo Field For&mat printdialogs6Formato de Campo para "{0}"Field Format for "{0}" printdialogs Ajuste de pginaFit Page printdialogsAjuste de ancho Fit Width printdialogs"E&stilo de fuente Font st&yle printdialogs &Pie:Foot&er: printdialogsPie Iz&quierdo Footer &Left printdialogsPie ce&ntradoFooter Ce&nter printdialogsPie De&recho Footer Righ&t printdialogs"A&yuda de Formato Format &Help printdialogsEncabe&zado:He&ader: printdialogs&Encabezado &Derecho Header &Right printdialogs(Encabezado cen&tradoHeader C&enter printdialogs4Encabezado y pie de pginaHeader and Footer printdialogsAltura:Height: printdialogsPulgadas (in) Inches (in) printdialogsNodos IncludosIncluded Nodes printdialogsSangrarIndent printdialogsbSangrado de &Salida (unidades de altura de lnea)"Indent Offse&t (line height units) printdialogsPaisa&je Lan&dscape printdialogs(Legal (8.5 x 14 in.)Legal (8.5 x 14 in.) printdialogs(Carta (8.5 x 11 in.)Letter (8.5 x 11 in.) printdialogsMrgenesMargins printdialogsMilmetros (mm)Millimeters (mm) printdialogs Pgina Siguiente Next Page printdialogs2Incluir solo nodos &hijosOnl&y open node children printdialogsOrientacin Orientation printdialogsSalida &FormatoOutput &Format printdialogs0Configuracin de &Pgina Page &Setup printdialogs"Tamao del Pape&l Paper &Size printdialogsRetra&to Portra&it printdialogsPgina anterior Previous Page printdialogsImprimirPrint printdialogs &Vista Previa...Print Pre&view... printdialogs2Vista Previa de Impresin Print Preview printdialogs4Configuracin de Impresin Print Setup printdialogs4Configuracin de ImpresinPrinting Setup printdialogsEjemploSample printdialogs,Seleccionar Im&presoraSelect &Printer printdialogs$Seleccionar Fuente Select Font printdialogs(&Ramas seleccionadasSelected &branches printdialogs(&Nodos seleccionadosSelected &nodes printdialogs&TamaoSi&ze printdialogsPgina sencilla Single Page printdialogs.Espacio entre colu&mnasSpace between colu&mns printdialogs,Tabloide (11 x 17 in.)Tabloid (11 x 17 in.) printdialogs,TreeLine Impresora PDFTreeLine PDF Printer printdialogsQu imprimir What to print printdialogsZoom AumentarZoom In printdialogsZorrm ReducirZoom Out printdialogs&Aadir&Add spellcheck&Cancelar&Cancel spellcheck&Ignorar todo &Ignore All spellcheck&Reemplazar&Replace spellcheck"Aadir &minsculaAdd &Lowercase spellcheckContexto:Context: spellcheckNo se pudo encontrar aspell.exe, ispell.exe o hunspell.exe Buscar la ubicacin?QCould not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? spellcheckTerminada revisin de la rama Continuar desde la parte superior?3Finished checking the branch Continue from the top? spellcheckFComprobacin ortogrfica finalizadaFinished spell checking spellcheckIgnor&arIgnor&e spellcheckXUbique aspell.exe, ipsell.exe o hunspell.exe-Locate aspell.exe, ipsell.exe or hunspell.exe spellcheck2No est en el diccionarioNot in Dictionary spellcheck Programa (*.exe)Program (*.exe) spellcheck Reem&plazar todo Re&place All spellcheck:Comprobacin de la ortografa Spell Check spellcheck"Error ortogrficoSpell Check Error spellcheckSugerencias Suggestions spellcheckHComprobacin ortogrfica de TreeLIneTreeLine Spell Check spellcheckError de comprobacin ortogrfica TreeLine Comprobar que est instalado aspell, ispell o hunspellLTreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed spellcheckPalabra:Word: spellcheck(Seleccionar en rbolSelect in Tree titlelistviewPREDETERMINADODEFAULT treeformats CAMPOFIELD treeformatsARCHIVOFILE treeformatsTipoCampo FieldType treeformatsFormatoFormat treeformats IconoIcon treeformatsTIPOTYPE treeformats&Negrita &Bold Fonttreelocalcontrol&Copiar&Copytreelocalcontrol&Eliminar Nodo &Delete Nodetreelocalcontrol&Separar Clones&Detach Clonestreelocalcontrol&Exportar... &Export...treelocalcontrol$Enlace &Externo...&External Link...treelocalcontrol"&Tamao de Fuente &Font Sizetreelocalcontrol&Sangrar Nodos &Indent Nodetreelocalcontrol&Cursiva &Italic FonttreelocalcontrolMover A&rriba&Move Uptreelocalcontrol&Nueva Ventana &New Windowtreelocalcontrol &Pegar&Pastetreelocalcontrol&Imprimir... &Print...treelocalcontrol&Rehacer&Redotreelocalcontrol,Re&generar Referencias&Regenerate Referencestreelocalcontrol&Renombrar&Renametreelocalcontrol&Guardar&Savetreelocalcontrol0&Establecer Tipo de Nodo&Set Node Typetreelocalcontrol2Corrector &Ortogrfico...&Spell Check...treelocalcontrol&Deshacer&Undotreelocalcontrol4Deshacer Sangrado de &Nodo&Unindent Nodetreelocalcontrol&Aadir Hijo Add &Childtreelocalcontrol:Aadir Ni&vel de Categora...Add Category &Level...treelocalcontrolNAadir nuevo hijo al padre seleccionado Add new child to selected parenttreelocalcontrolPAadir o modificar un enlace web externo!Add or modify an extrnal web linktreelocalcontrolVAadir o modificar un enlace interno a nodo#Add or modify an internal node linktreelocalcontrolRNo es posible expandir sin campos comunes#Cannot expand without common fieldstreelocalcontrol0Campos de las categorasCategory Fieldstreelocalcontrol&Borrar FormatoClear For&mattingtreelocalcontrolZBorrar actual o seleccionado formato de texto)Clear current or selected text formattingtreelocalcontrolFClonar &Todos los Nodos EmparejadosClone All &Matched Nodestreelocalcontrol`Contraer descendientes cuando se fusionen campos&Collapse descendants by merging fieldstreelocalcontrol`Convertir todos los nodos coincidentes en clones&Convert all matching nodes into clonestreelocalcontrol:Convierte ramas {0} en clones"Converted {0} branches into clonestreelocalcontrol<&Copiar Tipos desde Archivo...Copy Types from &File...treelocalcontrolLCopiar la rama o texto al portapapeles(Copy the branch or text to the clipboardtreelocalcontrollCopiar la configuracin desde otro archivo de TreeLine1Copy the configuration from another TreeLine filetreelocalcontrolCor&tarCu&ttreelocalcontrolRCortar la rama o el texto al portapapeles'Cut the branch or text to the clipboardtreelocalcontrolPredeterminadoDefaulttreelocalcontrol@Eliminar los nodos seleccionadosDelete the selected nodestreelocalcontrollSeparar todos los nodos clonados en las ramas actuales+Detach all cloned nodes in current branchestreelocalcontrolhError - No se puede borrar el archivo de respaldo {}'Error - could not delete backup file {}treelocalcontrolJError: no se pudo leer el archivo {0}Error - could not read file {0}treelocalcontrolRError - no se pudo escribir en el archivoError - could not write to filetreelocalcontrolBError - No se pudo escribir en {}Error - could not write to {}treelocalcontrolLExportar el archivo en varios formatos(Export the file in various other formatstreelocalcontroljExportar a PDF con las opciones de impresin actuales+Export to PDF with current printing optionstreelocalcontrol Archivo guardado File savedtreelocalcontrol,&Acoplar por CategoraFlatten &by Categorytreelocalcontrol&Color de &Fuente...Font C&olor...treelocalcontrolForzar actualizacin de todos los tipos condicionales y campos matemticos3Force update of all conditional types & math fieldstreelocalcontrol>Sangrar los nodos seleccionadosIndent the selected nodestreelocalcontrol.Aadir Hermano &DespusInsert Sibling &Aftertreelocalcontrol*Aadir &Hermano AntesInsert Sibling &BeforetreelocalcontrolvAadir los nodos con las categoras por encima de los hijos$Insert category nodes above childrentreelocalcontrolXAadir nuevo hermano despues de la seleccin"Insert new sibling after selectiontreelocalcontrolTAadir nuevo hermano antes de la seleccin#Insert new sibling before selectiontreelocalcontrol$Enlace &Interno...Internal &Link...treelocalcontrol GrandeLargetreelocalcontrolMs grandeLargertreelocalcontrolEl ms grandeLargesttreelocalcontrolMover Aba&jo M&ove Downtreelocalcontrol&Mover al &Principio Move &FirsttreelocalcontrolMover al &Final Move &LasttreelocalcontrolZDesplazar hacia abajo los nodos seleccionadosMove the selected nodes downtreelocalcontroljMover nodos seleccionados para ser los primeros hijos0Move the selected nodes to be the first childrentreelocalcontrolhMover nodos seleccionados para ser los ltimos hijos/Move the selected nodes to be the last childrentreelocalcontrol\Desplazar hacia arriba los nodos seleccionadosMove the selected nodes uptreelocalcontrol4No existen nodos idnticosNo identical nodes foundtreelocalcontrolRAbrir nueva ventana para el mismo archivo#Open a new window for the same filetreelocalcontrol<Config&uracin de Impresin...P&rint Setup...treelocalcontrol0Pegar Texto sin &FormatoPa&ste Plain TexttreelocalcontrolPegar &Hijo Paste C&hildtreelocalcontrol&Pegar Hijo C&lonadoPaste Cl&oned Childtreelocalcontrol8Pegar Hermano Clo&nado AntesPaste Clo&ned Sibling Beforetreelocalcontrol<Pegar Hermano Clonad&o DespusPaste Clone&d Sibling Aftertreelocalcontrol,Pegar Hermano Despu&sPaste Sibling &Aftertreelocalcontrol(Pegar Hermano &AntesPaste Sibling &BeforetreelocalcontrolPPegar hijo clonado desde el portapapeles&Paste a child clone from the clipboardtreelocalcontrolPPegar un nodo hijo desde el portapapeles%Paste a child node from the clipboardtreelocalcontrolPPegar un hermano despus de la seleccinPaste a sibling after selectiontreelocalcontrolFPegar hermano antes de la seleccin Paste a sibling before selectiontreelocalcontrolZPegar un clon hermano despus de la seleccin%Paste a sibling clone after selectiontreelocalcontrolVPegar un clon hermano antes de la seleccin&Paste a sibling clone before selectiontreelocalcontrolRPegar nodos o texto desde el portapapeles&Paste nodes or text from the clipboardtreelocalcontrolPPegar texto sin formato del portapapeles+Paste non-formatted text from the clipboardtreelocalcontrol$Imprimir a PD&F...Print &to PDF...treelocalcontrol:&Vista Previa de Impresin...Print Pre&view...treelocalcontrolpImprimir salida de rbol en base a las opciones actuales*Print tree output based on current optionstreelocalcontrol&Propiedades...Prop&erties...treelocalcontrolzRehacer la ltima accin sobre la que se ha aplicado deshacerRedo the previous undotreelocalcontrolTRenombrar ttulo completo del rbol en uso#Rename the current tree entry titletreelocalcontrolD&Intercambiar Niveles de CategoraS&wap Category Levelstreelocalcontrol Guardar &Como... Save &As...treelocalcontrolGuardar archivo Save Filetreelocalcontrol.Guardar cambios en {}?Save changes to {}?treelocalcontrol"Guardar cambios? Save changes?treelocalcontrol2Guardar el archivo actualSave the current filetreelocalcontrolLGuardar el archivo con un nombre nuevoSave the file with a new nametreelocalcontrolFSeleccionar campos para nuevo nivelSelect fields for new leveltreelocalcontrol0Definir tamao de fuente Set Font Sizetreelocalcontrol.Establecer tipo de nodo Set Node Typetreelocalcontrol~Establecer parmetros de archivo como compresin y encriptacin3Set file parameters like compression and encryptiontreelocalcontrolEstablecer mrgenes, tamao de pgina y otras opciones de impresin1Set margins, page size and other printing optionstreelocalcontrolhEstablecer el tamao del texto actual o seleccionado(Set size of the current or selected texttreelocalcontrolfEstablecer el color del texto actual o seleccionado-Set the color of the current or selected texttreelocalcontroljEstablecer la fuente actual o seleccionada en negrita(Set the current or selected font to boldtreelocalcontroljEstablecer la fuente actual o seleccionada en cursiva*Set the current or selected font to italictreelocalcontrolpEstablecer la fuente actual o seleccionada para subrayar-Set the current or selected font to underlinetreelocalcontrolhEstablecer tipo de nodo para los nodos seleccionados$Set the node type for selected nodestreelocalcontrolVVista previa de los resultados de impresin"Show a preview of printing resultstreelocalcontrolPequeoSmalltreelocalcontrolHRevisar los datos de texto del rbol Spell check the tree's text datatreelocalcontrolVIntercambiar categora nodos hijos y nietos(Swap child and grandchild category nodestreelocalcontrolRTreeLine - Abrir archivo de configuracin"TreeLine - Open Configuration Filetreelocalcontrol.TreeLine - Guardar comoTreeLine - Save Astreelocalcontrol&SubrayadoU&nderline Fonttreelocalcontrol6Deshacer la accin anteriorUndo the previous actiontreelocalcontrolXEliminar sangrado de los nodos seleccionadosUnindent the selected nodestreelocalcontrolAdvertencia: archivo corrupto! Se omitieron referencias de elementos secundarios incorrectos en los siguientes nodos:OWarning - file corruption! Skipped bad child references in the following nodes:treelocalcontrol,&Acerca de TreeLine...&About TreeLine...treemaincontrolUso &Bsico...&Basic Usage...treemaincontrol2&Cancelar archivo abierto&Cancel File Opentreemaincontrol0Bsqueda &Condicional...&Conditional Find...treemaincontrol:Configurar Tipos de &Datos...&Configure Data Types...treemaincontrol8Eliminar copia de segurida&d&Delete Backuptreemaincontrol &Buscar Texto... &Find Text...treemaincontrol4&Documentacin completa...&Full Documentation...treemaincontrol,Opciones &Generales...&General Options...treemaincontrolImporta&r... &Import...treemaincontrol&Nuevo...&New...treemaincontrol&Abrir...&Open...treemaincontrol &Salir&Quittreemaincontrol:&Restaurar copia de seguridad&Restore Backuptreemaincontrol"Seleccionar T&odo &Select Alltreemaincontrol(&Seleccionar Ejemplo&Select Sampletreemaincontrol,&Seleccionar Plantilla&Select Templatetreemaincontrol&Filtro de &Texto...&Text Filter...treemaincontrolExiste un archivo de respaldo: "{}". Una sesin anterior puede haberse bloqueadoAbrir un archivo desde el discoOpen a file from disktreemaincontrol<Abriri un arhchivo no-TreeLineOpen a non-TreeLine filetreemaincontrol6Abrir un archivo de ejemploOpen a sample filetreemaincontrolXReemplazar cadenas de texto en datos de nodo!Replace text strings in node datatreemaincontrolLSeleccionar todo el texto en un editorSelect all text in an editortreemaincontrol@Establecer &Atajos de Teclado...Set &Keyboard Shortcuts...treemaincontrolfConfigurar las preferencias para todos los archivos"Set user preferences for all filestreemaincontrolNMostrar Confi&guracin de Estructura... Show C&onfiguration Structure...treemaincontrolxMostrar visualizacin de solo lectura del tipo de estructura.Show read-only visualization of type structuretreemaincontrol"&Ordenar Nodos...Sor&t Nodes...treemaincontrol2Comenzar un archivo nuevoStart a new filetreemaincontrol0TreeLine - Abrir ArchivoTreeLine - Open Filetreemaincontrol&TreeLine Uso BsicoTreeLine Basic Usagetreemaincontrol(TreeLine version {0}TreeLine version {0}treemaincontrol2Actualizar &Numeracin...Update &Numbering...treemaincontrolPActualizar campos de numeracin de nodosUpdate node numbering fieldstreemaincontrolXUsar condiciones de campo para filtrar nodos$Use field conditions to filter nodestreemaincontrolZUse condiciones de campo para encontrar nodos"Use field conditions to find nodestreemaincontrolZAdvertencia: no se pudo crear el socket local'Warning: Could not create local sockettreemaincontrol0Directorio no encontradomissing directorytreemaincontrolescrito por {}written by {0}treemaincontrol NuevoNewtreenodePrincipalMain treestructureVFiltrado condicional, encontrados {0} nodos&Conditional filtering, found {0} nodestreeviewTFiltrando por "{0}", encontrados.{1} nodos#Filtering by "{0}", found {1} nodestreeviewSiguiente: {0} Next: {0}treeview>Siguiente: {0} (no encontrado)Next: {0} (not found)treeviewBuscar: Search for:treeviewBuscar {0}Search for: {0}treeview6Buscar {0} (no encontrado)Search for: {0} (not found)treeview&Cerrar Ventana &Close Window treewindow*&Reducir Toda la Rama&Collapse Full Branch treewindow &Datos&Data treewindow&Editar&Edit treewindow,&Expandir Toda la Rama&Expand Full Branch treewindow&Archivo&File treewindow A&yuda&Help treewindow(Seleccin &Siguiente&Next Selection treewindow &Nodo&Node treewindow"Seleccin &Previa&Previous Selection treewindow&Mostrar Panel &Hijo&Show Child Pane treewindow&Herramientas&Tools treewindow&Ver&View treewindowVen&tana&Window treewindow&Cerrar esta ventanaClose this window treewindowdReducir todos los hijos de los nodos seleccionados+Collapse all children of the selected nodes treewindowEditor de Datos Data Edit treewindowSalida de Datos Data Output treewindowfExpandir todos los hijos de los nodos seleccionados)Expand all children of the selected nodes treewindow&FormatoFo&rmat treewindowhIr a la siguiente seleccin de rbol en el historial(Go to the next tree selection in history treewindow<Bsqueda incremental siguienteNext Incremental Search treewindow:Bsqueda incremental anteriorPrevious Incremental Search treewindowNVolver a la seleccin de rbol anterior%Return to the previous tree selection treewindowDMostrar &vista panel de navegacinShow &Breadcrumb View treewindow2Mostrar &Lista de TtulosShow &Title List treewindow0Mostrar Editor de &DatosShow Data &Editor treewindow0&Mostrar Salida de DatosShow Data &Output treewindowPMostrar Salida de Datos y Des&cendientesShow Output &Descendants treewindowhMostrar el editor de datos en la vista de la derechaShow data editor in right view treewindow\Mostrar la salida de datos en la vista derechaShow data output in right view treewindowjMostrar la lista de ttulos en la vista de la derechaShow title list in right view treewindow8Iniciar bsqueda incrementalStart Incremental Search treewindow Lista de Ttulos Title List treewindow^Alternar mostrando vista anterior de navegacin'Toggle showing breadcrumb ancestor view treewindow|Alternar mostrando la vista de salida sangra de descendients/Toggle showing output view indented descendants treewindow:Alternar mostrando resultados%Toggle showing right-hand child views treewindowTreeLine-3.2.1/translations/treeline_pt.qm000066400000000000000000002405261506556630100206360ustar00rootroot00000000000000cg.AhDm3=x9e'VkW,j%6D0^^10KpW78[H5H5U;VE c ^/c2r5c`+e-d¬]E7~*h*yϞ***%*T*Eu*0*5i'+Ub+ҳ+++/+Gu+:+į*+/55S4 T;0$avS"'}Bw9w9v66wDԳ7ggc zCf6 {3 f3UP[y)$w%oMoC:U(]nﶰ~}6seyRy3ŏ|c %v>-$6nn6nb6n G^[R5<_ fc g|ۇ] #7/%U<nZ g̓wiaei~b~<~CjJu O4/%Yy7ctPW~הY#99ٞ@mD+NR p[ó7aLWXf@qgxi 5lwpѡoFszF}'.~oI.CtJz$@HF_VoZ F <$§#³:jGh w7o^|<.AU T.&=!L(M+5>?d@{$FJ\8\`}f4gNeh/rU|3s}8u`cPgG%5C~cQRJT(N!."k*+%["D9ϑ&Į0eT)שD,Y:KgDkH|S!5mcmtd-[ѤT~nJUn#CH#Cm*,9.//iW/0?,In3feL RSS"v+ZzZh]_Pb#|e,ffȊtglYr^(sPuh[ITi'.w~ |Ljϥ1M..R@v˃wΨ%@C7i_}E\>_f"^^4,.&k Y&t 2)&/0ndo7OT8OT!CdiP[FU'hSk#kNnMCnnD}\oj؎LN/ A!? [BeǨOe"upE(3p^ EfOdgųOa ; 'J,01cD1cD9Hks@ElFyLCf$W.[%d]!n#9wƾ{0>E !ccic$ IHnjT©&M~*)a9~o1 ^J !6%%z}%%xṄ/9:%{UKԤ?`޹߂_ߗevS+l^\m N \~7 \~m ;6h q#*s 4Eo 5f :ro Lx Mg f+>U k 8@  # ωsy ? b*8 ld| b   ʵ tX{ n 9 8 Y cY a  .t _ Tg W4Z ,_$. /2_ 4 5r 7* = ITR Ty  Wܾ5 _҉& ap cD c e ( uo u5 w5y; ăR_ 5A 1 : I I I I? Iv I I IP C] 9VN  m 6" 5 % 3w ^ I ; 2# t ˈ(= ĽNz ;: Gc! :q :w E/ w ;+ 5 e3 { : =  s .z& Q t{ Xf KA )M -8h .2& /. 2  5 @(e AZ K&= L. L9 W X [t# rWr x( C x( :32 u, sx g H   7 Zy i ;Q DG ( G D' B ~ t ٷ ߺ KG ~ \E#e X y~ 8 vs n N E AX +@\ P" % #: Q3 U '{ (ECF 7"* 8Ǒ\ ;y7 =: @E V dMY8 g#1 pk t" t$ t` v"; {B~3 =FD  eq h- MQ T^ B   C e m) ү\ vW bnT D U6  Y \L B 't . 0uI 0. 7y6 C ! G9. H4 Kz9m8 K M ]`^W _ _ dT& i2 i$h i$xQ z h 2 Q ݃ |@ =/k c' Dg sH ~t` >`-"J`s"sKZ(t-k/+0/Sy0>S+97= # EjVH;eL`#Lh?LeOL^V5Y&Zrjhj`kDlfc\p#Cq2tD -]txb tՋ:8ke-`EԕYe-h~ ;tp|VCg`;> uKc mR( 6t8 qa<s@-HNSI?M&UZ8n@[Ke3dem3J iFW=r^s$Lww }$74?y*A Բ6t$^DBpu2$&J|ɟ)];ݮo8d7F\3f6Yfb9i(;&Cancelar&Cancelcolorset&OK&OKcolorset*Adicionar &Nova Regra &Add New Rule conditional&Cancelar&Cancel conditional&Fechar&Close conditional&&Terminar Filtragem &End Filter conditionalF&iltrar&Filter conditional&OK&OK conditional&Eliminar Regra &Remove Rule conditional&Guardar&Save conditional FalsoFalse conditional&Encontrar &Seguinte Find &Next conditional&Encontrar &AnteriorFind &Previous conditionalLNenhum resultado satisfaz as condies!No conditional matches were found conditionalTipo de ramo Node Type conditionalRegra {0}Rule {0} conditionalVerdadeiroTrue conditional [Todos os Tipos] [All Types] conditionaleand conditional contmcontains conditionalacaba com ends with conditionalouor conditionalcomea com starts with conditional&Aplicar&Apply configdialog&Cancelar&Cancel configdialogTipo de &Dados &Data Type configdialog&Eliminar Tipo &Delete Type configdialog,&Derivadar de Original&Derive from original configdialog&Equao &Equation configdialog.C&onfigurao de Campos &Field Config configdialogT&ipo de Campo &Field Type configdialog$&Ocultar Avanadas&Hide Advanced configdialog"Mover para &Baixo &Move Down configdialog&Novo Campo... &New Field... configdialog&Novo Tipo... &New Type... configdialog&OK&OK configdialog&Prefixo&Prefix configdialog &Repor&Reset configdialog&&Tipo de Resultados &Result Type configdialog"&Seleccionar Tudo &Select All configdialog$&Mostrar Avanadas&Show Advanced configdialog0&Critrio de Ordenamento&Sort Criteria configdialog*&Formatao do Ttulo &Title Format configdialogHAdicionar linhas &vazias entre ramosAdd &blank lines between nodes configdialogAdicionar Campo Add Field configdialogAdicionar TipoAdd Type configdialogFAdicionar ou Remover Tipos de DadosAdd or Remove Data Types configdialog6Adicionar &pontos de tpicoAdd text bullet&s configdialogBPermitir texto formatado em &HTMLAllow &HTML rich text in format configdialog,Operadores AritmticosArithmetic Operators configdialog"Tipos AutomticosAutomatic Types configdialog8Lista de &Campos DisponveisAvailable &Field List configdialog&Campos &DisponveisAvailable &Fields configdialog"Resultado BoleanoBoolean Result configdialogvNo possivel apagar tipo de dados em utilizao por ramos+Cannot delete data type being used by nodes configdialogMudar &cone Change &Icon configdialog,Nmero de Descendentes Child Count configdialog2Referncia a DescendentesChild Reference configdialog &Limpar Seleco Clear &Select configdialogCo&piar Tipo... Co&py Type... configdialogzCarcter de &Separao de Combinaes e Lista de Descendentes+Combination && Child List Output &Separator configdialog0Operadores de ComparaoComparison Operators configdialog2Configurar Tipos de DadosConfigure Data Types configdialogCopiar Tipo Copy Type configdialog2&Criar Tipos CondicionaisCreate Co&nditional Types configdialog"Resultado de Data Date Result configdialogHValor pr &definido para novos ramosDefault &Value for New Nodes configdialogBTipo de &descendente pr definidoDefault Child &Type configdialogDefinir EquaoDefine Equation configdialogFDefinir equao do campo matemticoDefine Math Field Equation configdialog&Eliminar Campo Dele&te Field configdialog4&Derivado de Tipo GenricoDerived from &Generic Type configdialogDescrio Description configdialogDireco Direction configdialog:Altura da Caixa de Introduo Editor Height configdialog>Introduza o nome do novo campo:Enter new field name: configdialog@Introduza novo nome para o tipo:Enter new type name: configdialog&Erro na equao: {}Equation error: {} configdialogvErro - referncia cclica em equaes de campos matemticos2Error - circular reference in math field equations configdialogTexto adicional Extra Text configdialog Ca&mpoF&ield configdialog Li&sta de Campos F&ield List configdialog CampoField configdialog Lista de &Campos Field &List configdialog(Referncias a CamposField References configdialog6Informao sobre o ficheiroFile Info Reference configdialog$&Inverter DirecoFlip &Direction configdialog"&Ajuda de Formato Format &Help configdialog coneIcon configdialog$Equao Matemtica Math Equation configdialog4&Modificar Lista de CamposModify &Field List configdialog:&Modificar Tipos CondicionaisModify Co&nditional Types configdialog Mover para &CimaMove &Up configdialog"Mover para &Baixo Move Do&wn configdialog Mover para &cimaMove U&p configdialogNomeName configdialog NenhumNone configdialog4&Nmero de linhas de textoNum&ber of text lines configdialog"&Tipo de OperadorO&perator Type configdialog&ApresentaoO&utput configdialog(&Lista de OperadoresOper&ator List configdialogOperaes Operations configdialog4Referncias a outros campoOther Field References configdialog6&Formatao de ApresentaoOut&put Format configdialog0&Formato de ApresentaoOutpu&t Format configdialog,Opes de apresentaoOutput Options configdialog0Referncia a AscendentesParent Reference configdialog&&Tipo de RefernciaRefere&nce Type configdialog(&Nvel de RefernciaReference &Level configdialog&&Tipo de RefernciaReference &Type configdialog(&Nvel de RefernciaReference Le&vel configdialogM&udar Nome...Rena&me Field... configdialog &Mudar o Nome...Rena&me Type... configdialogMudar Nome Rename Field configdialog"Mudar Nome a Tipo Rename Type configdialog,Mudar nome de {} para:Rename from {} to: configdialog"Referncia RaizRoot Reference configdialogAuto RefernciaSelf Reference configdialog<Definir cone do Tipo de DadosSet Data Type Icon configdialog<Definir tipos condicionalmenteSet Types Conditionally configdialog:&Prioridade de Ordenamento... Sort &Keys... configdialog2Prioridade de OrdenamentoSort Key configdialog*Campos de OrdenamentoSort Key Fields configdialog&SufixoSuffi&x configdialog&Lista de Tipos T&ype List configdialog&Operadores de TextoText Operators configdialog"Resultado Textual Text Result configdialog\Os seguintes carcteres no so permitidos: {},The following characters are not allowed: {} configdialog2O nome no pode ser vazioThe name cannot be empty configdialog<O nome no pode conter espaosThe name cannot contain spaces configdialogBO nome no pode comear com "xml" The name cannot start with "xml" configdialogBO nome deve comear com uma letra!The name must start with a letter configdialog*Nome j em utilizaoThe name was already used configdialog$Resultado de Tempo Time Result configdialog,Configurao de &Tipos Typ&e Config configdialogTipoType configdialogT&Utilizar uma tabela para dados dos camposUse a table for field &data configdialog[Nenhum][None] configdialogvalor absolutoabsolute value configdialogadicionaradd configdialogarco coseno arc cosine configdialogarco senoarc sine configdialogarco tangente arc tangent configdialog mdiaaverage configdialog(logartmo de base 10base-10 logarithm configdialog concatenar textoconcatenate text configdialog>converter texto para minsculasconvert text to lower case configdialog>converter texto para maisculasconvert text to upper case configdialog$coseno de radianoscosine of radians configdialog&graus para radianosdegrees to radians configdialogdividirdivide configdialogigual aequal to configdialogfactorial factorial configdialogponto flutuantefloating point configdialog&Diviso arredondada floor divide configdialogDescendenteforward configdialogDescendentefwd configdialogmaior que greater than configdialogmaior ou igualgreater than or equal to configdialog inteiro superiorhigher integer configdialogxno 1 argumento, substituir o 2 argumento pelo 3 argumento(in 1st arg, replace 2nd arg with 3rd arg configdialogvjuntar texto utilizando o primeiro argumento como separador$join text using 1st arg as separator configdialogmenor que less than configdialog menor ou igual aless than or equal to configdialoge lgico logical and configdialogou lgico logical or configdialog inteiro inferior lower integer configdialog mximomaximum configdialog mnimominimum configdialog restomodulus configdialogmultiplicarmultiply configdialog8constante logartmo natural natural log constant configdialog"logartmo naturalnatural logarithm configdialogdiferente de not equal to configdialogconstante pi pi constant configdialogpotnciapower configdialog&radianos para grausradians to degrees configdialogAscendenterev configdialogAscendentereverse configdialog2arredondar para x dgitosround to num digits configdialog seno de radianossine of radians configdialograiz quadrada square root configdialogsubtrairsubtract configdialogsumatrio sum of items configdialog(tangente de radianostangent of radians configdialogzverdadeiro se o 1 argumento de texto contiver o 2 argumento%true if 1st text arg contains 2nd arg configdialogverdadeiro se o 1 argumento de texto terminar com o 2 argumento&true if 1st text arg ends with 2nd arg configdialogverdadeiro se o 1 argumento de texto comear com o 2 argumento(true if 1st text arg starts with 2nd arg configdialogNvalor verdadeiro, condio, valor falso"true value, condition, false value configdialog inteiro truncadotruncated integer configdialog$Procurar &Ficheiro&Browse for File dataeditors&Cancelar&Cancel dataeditors &Ir para Destino &Go to Target dataeditors&OK&OK dataeditors&Abrir Ligao &Open Link dataeditors&Abrir Imagem &Open Picture dataeditorsAbsolutoAbsolute dataeditorsEndereoAddress dataeditors*Texto de Apresentao Display Name dataeditorsLigao Externa External Link dataeditors>Tipo de Caminho para o FicheiroFile Path Type dataeditorsLigao Interna Internal Link dataeditorsAbrir &Pasta Open &Folder dataeditors&Ligao para imagem Picture Link dataeditorsRelativoRelative dataeditorsProtocoloScheme dataeditorsData de &Hoje Today's &Date dataeditorsPTreeLine - Ligao para Ficheiro ExternoTreeLine - External Link File dataeditors:TreeLine - Ficheiro de ImagemTreeLine - Picture File dataeditors&Colunas&Columnsexportsrvore &Inteira &Entire treeexports &HTML&HTMLexports4Favoritos em formato &HTML&HTML format bookmarksexportsndice &ODF &ODF Outlineexports>&Apenas descendentes expandidos&Only open node childrenexports$HTML Pgina &nica&Single HTML pageexports@&Ttulos separados por tabulao&Tabbed title textexports &Texto&TextexportsXContedo no &formatado para todos os textos&Unformatted output of all textexports4Favoritos em formato &XBEL&XBEL format bookmarksexports&Favoritos Book&marksexportsFavoritos BookmarksexportsTEscolha o subtipo do formato de exportaoChoose export format subtypeexports>Escolha o formato de exportaoChoose export format typeexports>Escolha as opes de exportaoChoose export optionsexports.Exportao de ficheiros File ExportexportsPIncluir &cabealho e rodap de impressoInclude &print header && footerexportsbMultiplas pginas HTML com &tabelas de informaoMultiple HTML &data tablesexports\&Multiplas pginas HTML com barra de navegao)Multiple HTML &pages with navigation paneexports:&Nveis da barra de navegaoNavigation pane &levelsexportsOutras Opes Other Optionsexports.&Subramos SeleccionadosSelected &branchesexports(&Ramos SeleccionadosSelected &nodesexportsRHTML pgina nica com barra de &navegao&Single &HTML page with navigation paneexports@TreeLine - Exportar XML GenricoTreeLine - Export Generic XMLexports0TreeLine - Exportar HTMLTreeLine - Export HTMLexportsJTreeLine - Exportar Favoritos em HTML TreeLine - Export HTML Bookmarksexports:TreeLine - Exportar Texto ODFTreeLine - Export ODF TextexportsBTreeLine - Exportar Texto SimplesTreeLine - Export Plain TextexportsHTreeLine - Exportar Tabelas de TextoTreeLine - Export Text TablesexportsHTreeLine - Exportar Texto de TtulosTreeLine - Export Text TitlesexportsNTreeLine - Exportar Sub rvore TreeLine"TreeLine - Export TreeLine SubtreeexportsJTreeLine - Exportar Favoritos em XBEL TreeLine - Export XBEL BookmarksexportsO que exportarWhat to ExportexportsCarcter "." .."." Character .. fieldformatCarcter "/" //"/" Character // fieldformat&0 Ou 1 Repeties ?0 Or 1 Repetitions ? fieldformat,0 ou Mais Repeties *0 Or More Repetitions * fieldformat,1 Ou Mais Repeties +1 Or More Repetitions + fieldformat&Qualquer carcter .Any Character . fieldformatAutoEscolha AutoChoice fieldformatAutoCombinaoAutoCombination fieldformatBoleanoBoolean fieldformat"Letra Maiscula ACapital Letter A fieldformat4Numeral Romano Maisculo ICapital Roman Numeral I fieldformatEscolhaChoice fieldformatCombinao Combination fieldformatDataDate fieldformat"Vrgula Decimal ,Decimal Comma , fieldformatPonto Decimal .Decimal Point . fieldformatDDgito ou espao (externo) <space>!Digit or Space (external)  fieldformatFim de texto $ End of Text $ fieldformat8Terminar Carcter Especial \Escape a Special Character \ fieldformatExemplo 1/2/3/4Example 1/2/3/4 fieldformat.Exponente (maiscula) EExponent (capital) E fieldformat.Exponente (minscula) eExponent (small) e fieldformatLigaoExterna ExternalLink fieldformatTextoHTMLHtmlText fieldformatLigaoInterna InternalLink fieldformat(Separador de Nvel /Level Separator / fieldformat.Letras Minsculas [a-z]Lower Case Letters [a-z] fieldformatMatemticaMath fieldformat8Carcter no numrico [^0-9]Not a Number [^0-9] fieldformat AgoraNow fieldformat NmeroNumber fieldformatNmero 1Number 1 fieldformatNumerao Numbering fieldformatTextoLinhaUnica OneLineText fieldformat"Dgito Opcional #Optional Digit # fieldformat Sinal Opcional -Optional Sign - fieldformatOu |Or | fieldformatFExemplo de ndice I../A../1../a)/i)!Outline Example I../A../1../a)/i) fieldformat ImagemPicture fieldformat ExpressoRegularRegularExpression fieldformat(Dgito Obrigatrio 0Required Digit 0 fieldformat&Sinal Obrigatrio +Required Sign + fieldformat2Exemplo de Seco 1.1.1.1Section Example 1.1.1.1 fieldformat*Separador de Seco .Section Separator . fieldformatSeparador / Separator / fieldformat2Conjunto de Nmeros [0-9]Set of Numbers [0-9] fieldformat"Letra Minscula aSmall Letter a fieldformat4Numeral Romano Minsculo iSmall Roman Numeral i fieldformatJEspao de Separao (interno) <space>"Space Separator (internal)  fieldformatTextoEspaado SpacedText fieldformatV/FT/F fieldformat TextoText fieldformat TempoTime fieldformat.Letras Maisculas [A-Z]Upper Case Letters [A-Z] fieldformatS/NY/N fieldformat verdadeiro/falso true/false fieldformatsim/noyes/no fieldformat falsofalse genbooleannono genbooleanverdadeirotrue genbooleansimyes genboolean$Todos os Ficheiros All Files globalrefFicheiros HTML HTML Files globalrefFicheiros ODFODF Text Files globalrefFicheiros PDF PDF Files globalref$Ficheiros de Texto Text Files globalref$Ficheiros TreeLineTreeLine Files globalref@Ficheiros TreeLine - ComprimidosTreeLine Files - Compressed globalref@Ficheiros TreeLine - EncriptadosTreeLine Files - Encrypted globalref"Ficheiros Treepad Treepad Files globalrefFicheiros XML XML Files globalrefEncontrar:  Find: helpview&Retroceder&Backhelpview&Avanar&Forwardhelpview&Incio&Homehelpview&Encontrar &Seguinte Find &Nexthelpview&Encontrar &AnteriorFind &Previoushelpview(Texto no encontradoText string not foundhelpviewFerramentasToolshelpview"{0}" no um ficheiro TreeLine vlido. Utilizar um filtro de importao?:"{0}" is not a valid TreeLine file. Use an import filter?importsf&XML Genrico (ficheiro no especfico do TreeLine) &Generic XML (non-TreeLine file)importsHFavoritos em &HTML (Formato Mozilla) &HTML bookmarks (Mozilla Format)imports^&Texto recuado por tabulao, um ramo por linha%&Tab indented text, one node per lineimports:&Favoritos XML (Formato XBEL)&XML bookmarks (XBEL format)importsFAVORITOBOOKMARKimportsFavoritos Bookmarksimports:Escolher Mtodo de ImportaoChoose Import MethodimportsTErro - no foi possvel ler o ficheiro {0}Error - could not read file {0}importsPErro - formato de ficheiro imprprio {0}Error - improper format in {0}imports PASTAFOLDERimports"Importar Ficheiro Import Fileimports"Ficheiro Invlido Invalid FileimportsLigaoLinkimports6ndice &Open Document (ODF)Open &Document (ODF) outlineimports|&Pargrafos de texto simples (delimitados por linha em branco)-Plain text ¶graphs (blank line delimited)importsSEPARADOR SEPARATORimports TABELATABLEimportsTabela de texto delimitada por tabulao com &cabealhos e colunas)Tab delimited text table with header &rowimports TextoTextimports8TreeLine - Importar FicheiroTreeLine - Import FileimportsR&Ficheiro Treepad (ramos de texto apenas)Treepad &file (text nodes only)importsvReferncias a descendentes devem ser combinadas numa funo/Child references must be combined in a functionmatheval0Carcteres "{0}" ilegaisIllegal "{}" charactersmatheval6Funo ilegal presente: {0}Illegal function present: {0}mathevalNOperador ou tipo de objecto ilegal: {0}$Illegal object type or operator: {0}matheval2Sintaxe ilegal na equaoIllegal syntax in equationmatheval&Aplicar&Apply miscdialogs&Cancelar&Cancel miscdialogs&Fechar&Close miscdialogs &Terminar Filtro &End Filter miscdialogs&Toda a rvore &Entire tree miscdialogs&Filtrar&Filter miscdialogs&Encontrar &Seguinte &Find Next miscdialogs&Ascendente&Forward miscdialogs"&Ignorar e saltar&Ignore and skip miscdialogs0&Palavras chave parciais &Key words miscdialogs&Tipo de ramo &Node Type miscdialogs&OK&OK miscdialogsH&Campos de ordenamento pr definidos&Predefined Key Fields miscdialogs$&Expresso regular&Regular expression miscdialogs&Substituir&Replace miscdialogsP&Reiniciar contagem para prximos irmos"&Restart numbers for next siblings miscdialogs2&Restaurar pr definies&Restore Defaults miscdialogs&Descendente&Reverse miscdialogs &Pesquisar Texto &Search Text miscdialogs2&Descendentes da Seleco&Selection's children miscdialogsApenas &Ttulos &Titles only miscdialogs,&Barras de Ferramentas &Toolbars miscdialogs@&Tratar campos vazios como zeros&Treat blank fields as zeros miscdialogs@Utilizar &compresso de ficheiro&Use file compression miscdialogsNUtilizar fonte pr definida do &sistema&Use system default font miscdialogs--Separador-- --Separator-- miscdialogs*Comandos &DisponveisA&vailable Commands miscdialogs(&Qualquer ocorrncia Any &match miscdialogs&Remover Atalho Clear &Key miscdialogsBPersonalizar Barra de FerramentasCustomize Toolbars miscdialogsInformaoData miscdialogsMenu Informao Data Menu miscdialogsFPr definido - Texto em linha nicaDefault - Single Line Text miscdialogs EditarEdit miscdialogsMenu Editar Edit Menu miscdialogs@Tipo de Letra da Vista de EdioEditor View Font miscdialogsHPalavra Passe de Ficheiro EncriptadoEncrypted File Password miscdialogsBErro - Expresso Regular invlida"Error - invalid regular expression miscdialogs4Erro - substituio falhouError - replacement failed miscdialogs&Frase completa F&ull phrase miscdialogs CamposFields miscdialogsFicheiroFile miscdialogsMenu Ficheiro File Menu miscdialogs0Propriedades do FicheiroFile Properties miscdialogs2Armazenamento do Ficheiro File Storage miscdialogsFiltrarFilter miscdialogsEncontrarFind miscdialogs&Encontrar &Seguinte Find &Next miscdialogs&Encontrar &AnteriorFind &Previous miscdialogs,Encontrar e SubstituirFind and Replace miscdialogs$Toda a &informao Full &data miscdialogs&Palavras &Completas Full &words miscdialogsVCritrio para Ramos sem Campos de Numerao'Handling Nodes without Numbering Fields miscdialogs AjudaHelp miscdialogsMenu Ajuda Help Menu miscdialogsComo pesquisar How to Search miscdialogsDIcluir ramos dos nveis superioresInclude top-level nodes miscdialogs2Palavras chave &completasKey full &words miscdialogs4Tecla {0} j em utilizaoKey {0} is already used miscdialogs$Atalhos de TecladoKeyboard Shortcuts miscdialogsXCdigo de linguagem ou dicionrio (opcional)&Language code or dictionary (optional) miscdialogscones Grandes Large Icons miscdialogs$Campos Matemticos Math Fields miscdialogs"Mover para &Baixo Move &Down miscdialogs Mover para &CimaMove &Up miscdialogs"&Campos dos Ramos N&ode Fields miscdialogsxNo foram encontrados campos de numerao nos tipos de dados,No numbering fields were found in data types miscdialogsRamoNode miscdialogs$Ttulos dos &Ramos Node &Titles miscdialogsMenu Ramo Node Menu miscdialogs:Tipo de Letra de ApresentaoOutput View Font miscdialogs$&Expresso regularRe&gular expression miscdialogs:Re-Introduza a Palavra Passe:Re-Type Password: miscdialogsTPalavras passe introduzidas so diferentesRe-typed password did not match miscdialogsVLembrar a palavra passe durante esta sesso%Remember password during this session miscdialogs"Substituir &Todos Replace &All miscdialogsDForam substituidas {0} ocorrnciasReplaced {0} matches miscdialogs,Texto de &SubstituioReplacement &Text miscdialogs"&Reservar nmerosReserve &numbers miscdialogsRaiz Root Node miscdialogsPTermos de pesquisa "{0}" no encontradosSearch string "{0}" not found miscdialogsLTermo de pesquisa "{0}" no encontradoSearch text "{0}" not found miscdialogs(Ramos &SeleccionadosSelected &branches miscdialogs&&Irmos da selecoSelection's &siblings miscdialogs2&Descendentes da selecoSelection's childre&n miscdialogscones Pequenos Small Icons miscdialogs.Direco de OrdenamentoSort Direction miscdialogs*Mtodo de Ordenamento Sort Method miscdialogsOrdenar Ramos Sort Nodes miscdialogs(Verificar Ortografia Spell Check miscdialogsBComandos da &Barra de FerramentasTool&bar Commands miscdialogs@&Tamanho da Barra de Ferramentas Toolbar &Size miscdialogs>Nmero de Barras de FerramentasToolbar Quantity miscdialogsFerramentasTools miscdialogs Menu Ferramentas Tools Menu miscdialogs.Tipo de Letra da rvoreTree View Font miscdialogs$Numerao TreeLineTreeLine Numbering miscdialogsJIntroduza a palavra passe para "{0}":Type Password for "{0}": miscdialogs4Introduza a Palavra Passe:Type Password: miscdialogs<Actualizar Numerao dos RamosUpdate Node Numbering miscdialogsBUtilizar &encriptao de ficheiroUse file &encryption miscdialogsVerView miscdialogsMenu Ver View Menu miscdialogsOnde pesquisarWhat to Search miscdialogsO que Ordenar What to Sort miscdialogs O que ActualizarWhat to Update miscdialogs JanelaWindow miscdialogsMenu Janela Window Menu miscdialogsPPalavras passe vazias no so permitidas'Zero-length passwords are not permitted miscdialogs"[Todos os Campos] [All Fields] miscdialogs [Todos os Tipos] [All Types] miscdialogsNomeName nodeformatAparncia Appearanceoptiondefaults&Gravao Automtica Auto Saveoptiondefaults^Abrir automaticamente ltimo ficheiro utilizado!Automatically open last file usedoptiondefaultspRecuo dos descendentes (em unidades de altura da fonte) +Child indent offset (in font height units) optiondefaultsDClicar nos ramos para alterar nomeClick node to renameoptiondefaults6Formatos do Editor de DadosData Editor Formatsoptiondefaults DatasDatesoptiondefaults6Funcionalidades DisponveisFeatures Availableoptiondefaults,Primeiro dia da semanaFirst day of weekoptiondefaultsSexta-FeiraFridayoptiondefaultsJMinutos entre gravaes (0 desactiva)+Minutes between saves (set to 0 to disable)optiondefaultsSegunda-FeiraMondayoptiondefaults\Nmero de ficheiros recentes no menu ficheiro(Number of recent files in the file menuoptiondefaults6Nmero de passos a desfazerNumber of undo levelsoptiondefaults@Abrir ficheiros em novas janelasOpen files in new windowsoptiondefaults$Ficheiros Recentes Recent FilesoptiondefaultsBEditar nome de ramos aps criaoRename new nodes when createdoptiondefaultsLRepor a anterior disposio de janelas Restore previous window geometryoptiondefaultsrRestaurar o estado de visualizao dos ficheiros recentes(Restore tree view states of recent filesoptiondefaults SbadoSaturdayoptiondefaultsZMostrar descendentes na vista de apresentaoShow descendants in output viewoptiondefaultsBMostrar cones na vista em rvoreShow icons in the tree viewoptiondefaultsZMostrar campos matemticos na Vista de Edio&Show math fields in the Data Edit viewoptiondefaults\Mostrar campos de numerao na Vista de Edio+Show numbering fields in the Data Edit viewoptiondefaults$Opes de ArranqueStartup ConditionoptiondefaultsDomingoSundayoptiondefaultsQuinta-FeiraThursdayoptiondefaults TempoTimesoptiondefaultsZPermitir arrastar e largar na vista da rvoreTree drag && drop availableoptiondefaultsTera-FeiraTuesdayoptiondefaults(Memria de operaes Undo MemoryoptiondefaultsQuarta-Feira Wednesdayoptiondefaults&Cancelar&Canceloptions&OK&OKoptions`Escolher localizao do ficheiro de configurao"Choose configuration file locationoptionsXPasta do programa (para utilizao porttil)$Program directory (for portable use)optionsBPasta do utilizador (recomendado)#User's home directory (recommended)options8Erro ao iniciar a impressoraError initializing printer printdata.TreeLine - Exportar PDFTreeLine - Export PDF printdata &Base:&Bottom: printdialogs&Cancelar&Cancel printdialogsB&Desenhar linhas at descendentes&Draw lines to children printdialogs &rvore completa &Entire tree printdialogs &Fonte&Font printdialogs$Seleco de &Fonte&Font Selection printdialogs&Opes Gerais&General Options printdialogs,&Esquerda do Cabealho &Header Left printdialogs"&Cabealho/Rodap&Header/Footer printdialogs&Incluir Raiz&Include root node printdialogsZ&Manter primeiro descendente com o ascendente&Keep first child with parent printdialogs&Esquerda:&Left: printdialogs$&Nmero de colunas&Number of columns printdialogs&OK&OK printdialogs&Prefixo&Prefix printdialogs&Imprimir... &Print... printdialogs&Direita:&Right: printdialogs&Sufixo&Suffix printdialogs &Topo:&Top: printdialogs&Unidades&Units printdialogs\Utilizar a fonte de apresentao do &TreeLine &Use TreeLine output view font printdialogs&Largura:&Width: printdialogs"A3 (279 x 420 mm)A3 (279 x 420 mm) printdialogs"A4 (210 x 297 mm)A4 (210 x 297 mm) printdialogs"A5 (148 x 210 mm)A5 (148 x 210 mm) printdialogs>AaBbCcDdEeFfGg...TtUuVvWvXxYyZzAaBbCcDdEeFfGg...TtUuVvWvXxYyZz printdialogs Centmetros (cm)Centimeters (cm) printdialogsColunasColumns printdialogs*Tamanho personalizado Custom Size printdialogs$Fonte Pr Definida Default Font printdialogsTexto Extra Extra Text printdialogs(Pginas Consecutivas Facing Pages printdialogs OpesFeatures printdialogs&CamposFiel&ds printdialogs&&Formato dos Campos Field For&mat printdialogs6Formato de campo para "{0}"Field Format for "{0}" printdialogs Ajustar PginaFit Page printdialogs"Ajustar Largura Fit Width printdialogs &Estilo de Fonte Font st&yle printdialogs&Rodap:Foot&er: printdialogs&E&squerda do Rodap Footer &Left printdialogs$Ce&ntro do RodapFooter Ce&nter printdialogs$Direi&ta do Rodap Footer Righ&t printdialogs"&Ajuda de Formato Format &Help printdialogs&Cabealho:He&ader: printdialogs*&Direita do Cabealho Header &Right printdialogs(&Centro do CabealhoHeader C&enter printdialogs$Cabealho e RodapHeader and Footer printdialogsAltura:Height: printdialogsPolegadas (pol) Inches (in) printdialogsRamos IncludosIncluded Nodes printdialogs AvanoIndent printdialogsj&Distancia do Avano (em unidades de altura de linha)"Indent Offse&t (line height units) printdialogsAo &alto Lan&dscape printdialogs*Legal (8.5 x 14 pol.)Legal (8.5 x 14 in.) printdialogs*Carta (8.5 x 11 pol.)Letter (8.5 x 11 in.) printdialogsMargensMargins printdialogsMilmetros (mm)Millimeters (mm) printdialogsPgina Seguinte Next Page printdialogsPApenas descendentes de ramos &expandidosOnl&y open node children printdialogsOrientao Orientation printdialogs0Formato de &ApresentaoOutput &Format printdialogs.Configurao de &Pgina Page &Setup printdialogs"&Tamanho do Papel Paper &Size printdialogsAo &baixo Portra&it printdialogsPgina Anterior Previous Page printdialogsImprimirPrint printdialogs@&Previsualizao de Impresso...Print Pre&view... printdialogs8Previsualizao de Impresso Print Preview printdialogs.Definies de Impresso Print Setup printdialogs&Opes de impressoPrinting Setup printdialogsAmostraSample printdialogs"Seleccionar Fonte Select Font printdialogsF&Ramos e descendentes seleccionadosSelected &branches printdialogs(Ramos &SeleccioandosSelected &nodes printdialogs&TamanhoSi&ze printdialogsPgina nica Single Page printdialogs4&Espaamento entre colunasSpace between colu&mns printdialogs.Tablide (11 x 17 pol.)Tabloid (11 x 17 in.) printdialogsO que imprimir What to print printdialogsAproximarZoom In printdialogsAfastarZoom Out printdialogs&Adicionar&Add spellcheck&Cancelar&Cancel spellcheckIgnorar &Todas &Ignore All spellcheck&Substituir&Replace spellcheck0Adicionar em &MinsculasAdd &Lowercase spellcheckContexto:Context: spellcheckNo foi possvel encontrar aspell.exe, ispell.exe ou hunspell.exe Procurar localizao?QCould not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? spellcheckBTerminada verificao ortogrficaFinished spell checking spellcheck&IgnorarIgnor&e spellcheck`Localizar aspell.exe, ispell.exe ou hunspell.exe-Locate aspell.exe, ipsell.exe or hunspell.exe spellcheck*Ausente no DicionrioNot in Dictionary spellcheck Programa (*.exe)Program (*.exe) spellcheck"S&ubstituir Todas Re&place All spellcheck.Verificao Ortogrfica Spell Check spellcheck>Erro de Verificao OrtogrficaSpell Check Error spellcheckSugestes Suggestions spellcheck@Verificao Ortogrfica TreeLineTreeLine Spell Check spellcheckErro de verificao Ortogrfica do TreeLine Cerifique-se que aspell, ispell ou hunspell esto instaladosLTreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed spellcheckPalavra:Word: spellcheckPR DEFINIDODEFAULT treeformats coneIcon treeformats&Negrito &Bold Fonttreelocalcontrol&Copiar&Copytreelocalcontrol&Eliminar Ramo &Delete Nodetreelocalcontrol&Exportar... &Export...treelocalcontrol&&Ligao Externa...&External Link...treelocalcontrol"&Tamanho do texto &Font Sizetreelocalcontrol&Recuar Ramo &Indent Nodetreelocalcontrol&Itlico &Italic Fonttreelocalcontrol Mover para &Cima&Move Uptreelocalcontrol&Nova Janela &New Windowtreelocalcontrol C&olar&Pastetreelocalcontrol&Imprimir... &Print...treelocalcontrol&Refazer&Redotreelocalcontrol&Mudar Nome&Renametreelocalcontrol&Guardar&Savetreelocalcontrol*Definir &Tipo de Ramo&Set Node Typetreelocalcontrol0&Verificar Ortografia...&Spell Check...treelocalcontrol&Desfazer&UndotreelocalcontrolA&vanar Ramo&Unindent Nodetreelocalcontrol,Adicionar De&scendente Add &ChildtreelocalcontrolB&Adicionar Nvel por Categoria...Add Category &Level...treelocalcontrolNAdicionar sub ramo ao ramo seleccionado Add new child to selected parenttreelocalcontroltAdicionar ou modificar uma ligao externa para a internet!Add or modify an extrnal web linktreelocalcontroltAdicionar ou modificar uma ligao interna para outro ramo#Add or modify an internal node linktreelocalcontrolVNo possvel expandir sem campos em comum#Cannot expand without common fieldstreelocalcontrol(Campos de CategoriasCategory Fieldstreelocalcontrol$Limpar &FormataoClear For&mattingtreelocalcontrolhRemover a formatao do texto actual ou seleccionado)Clear current or selected text formattingtreelocalcontrolJColapsar descendentes juntando campos&Collapse descendants by merging fieldstreelocalcontrolDCopiar Tipos de Outro &Ficheiro...Copy Types from &File...treelocalcontrolbCopiar o ramo ou texto para a memria de trabalho(Copy the branch or text to the clipboardtreelocalcontrol\Copiar configurao de outro ficheiro TreeLine1Copy the configuration from another TreeLine filetreelocalcontrolCor&tarCu&ttreelocalcontrolbCortar o ramo ou texto para a memria de trabalho'Cut the branch or text to the clipboardtreelocalcontrol NormalDefaulttreelocalcontrol>Eliminar os ramos seleccionadosDelete the selected nodestreelocalcontrolhErro - no foi possvel apagar cpia de segurana {}'Error - could not delete backup file {}treelocalcontrolTErro - no foi possvel ler o ficheiro {0}Error - could not read file {0}treelocalcontrol`Erro - no foi possvel escrever para o ficheiroError - could not write to filetreelocalcontrolLErro - no possvel escrever para {}Error - could not write to {}treelocalcontrol^Exportar o ficheiro em diversos outros formatos(Export the file in various other formatstreelocalcontrolhExportar para PDF com as actuais opes de impresso+Export to PDF with current printing optionstreelocalcontrol Ficheiro gravado File savedtreelocalcontrol,&Nivelar por categoriaFlatten &by Categorytreelocalcontrol Co&r do Texto...Font C&olor...treelocalcontrol<Avanar os ramos seleccionadosIndent the selected nodestreelocalcontrol*Inserir Irmo &DepoisInsert Sibling &Aftertreelocalcontrol(Inserir Irmo &AntesInsert Sibling &Beforetreelocalcontrol~Insere ramos sobre descendentes classificanado segundo um campo$Insert category nodes above childrentreelocalcontrolHInserir novo ramo abaixo da seleco"Insert new sibling after selectiontreelocalcontrolFInserir novo ramo acima da seleco#Insert new sibling before selectiontreelocalcontrol&Ligao &Interna...Internal &Link...treelocalcontrol GrandeLargetreelocalcontrol MaiorLargertreelocalcontrolMuito GrandeLargesttreelocalcontrol"Mover para &Baixo M&ove Downtreelocalcontrol(Colocar em &Primeiro Move &Firsttreelocalcontrol$Colocar em &ltimo Move &LasttreelocalcontrolNMover para baixo os ramos seleccionadosMove the selected nodes downtreelocalcontrolMover os ramos seleccionados para que sejam os primeiros descendentes0Move the selected nodes to be the first childrentreelocalcontrolMover os ramos seleccionados para que sejam os ltimos descendentes/Move the selected nodes to be the last childrentreelocalcontrolLMover para cima os ramos seleccionadosMove the selected nodes uptreelocalcontrolDAbrir nova vista do mesmo ficheiro#Open a new window for the same filetreelocalcontrol6&Definies de Impresso...P&rint Setup...treelocalcontrolVColar ramos ou texto da memria de trabalho&Paste nodes or text from the clipboardtreelocalcontrolbColar texto sem formatao da memria de trabalho+Paste non-formatted text from the clipboardtreelocalcontrol*Imprimir para &PDF...Print &to PDF...treelocalcontrol8Pr &visualizar impresso...Print Pre&view...treelocalcontroltImprimir apresentao da rvore baseada nas opes actuais*Print tree output based on current optionstreelocalcontrol &Propriedades...Prop&erties...treelocalcontrol:Repe a ltima aco desfeitaRedo the previous undotreelocalcontrolTAlterar o nome da entrada actual na rvore#Rename the current tree entry titletreelocalcontrol Guardar &Como... Save &As...treelocalcontrol Guardar Ficheiro Save Filetreelocalcontrol2Guardar alteraes em {}?Save changes to {}?treelocalcontrol&Guardar alteraes? Save changes?treelocalcontrol2Guardar o ficheiro actualSave the current filetreelocalcontrolFGuardar o ficheiro com um novo nomeSave the file with a new nametreelocalcontrol@Seleccione campo para novo nvelSelect fields for new leveltreelocalcontrol0Definir tamanho do texto Set Font Sizetreelocalcontrol(Definir Tipo de Ramo Set Node TypetreelocalcontrolxDefinir parmetros do ficheiro como compresso e encriptao3Set file parameters like compression and encryptiontreelocalcontrol|Definir margens, tamanho de papel e outras opes de impresso1Set margins, page size and other printing optionstreelocalcontrolbDefinir o tamanho do texto actual ou seleccionado(Set size of the current or selected texttreelocalcontrolZDefinir a cor do texto actual ou seleccionado-Set the color of the current or selected texttreelocalcontrolfDefinir o texto actual ou seleccionado como negrito(Set the current or selected font to boldtreelocalcontrolfDefinir o texto actual ou seleccionado como itlico*Set the current or selected font to italictreelocalcontrollDefinir o texto actual ou seleccionado como sublinhado-Set the current or selected font to underlinetreelocalcontrolfDefinir o tipo de dados para os ramos seleccionados$Set the node type for selected nodestreelocalcontrollMostrar uma pr visualizao do resultado da impresso"Show a preview of printing resultstreelocalcontrolPequenoSmalltreelocalcontrolRTreeLine - Abrir Ficheiro de Configurao"TreeLine - Open Configuration Filetreelocalcontrol.TreeLine - Guardar ComoTreeLine - Save Astreelocalcontrol&SublinhadoU&nderline Fonttreelocalcontrol,Reverte a ltima acoUndo the previous actiontreelocalcontrol:Recuar os ramos seleccionadosUnindent the selected nodestreelocalcontrol,&Acerca do TreeLine...&About TreeLine...treemaincontrol*Utilizao &Bsica...&Basic Usage...treemaincontrol<&Cancelar Abertura de Ficheiro&Cancel File Opentreemaincontrol.&Procura Condicional...&Conditional Find...treemaincontrol:&Configurar Tipos de Dados...&Configure Data Types...treemaincontrol4&Apagar Cpia de Segurana&Delete Backuptreemaincontrol&&Encontrar Texto... &Find Text...treemaincontrol2&Documentao Completa...&Full Documentation...treemaincontrol"&Opes Gerais...&General Options...treemaincontrol&Importar... &Import...treemaincontrol&Novo...&New...treemaincontrol&Abrir...&Open...treemaincontrol &Sair&Quittreemaincontrol:&Restaurar Cpia de Segurana&Restore Backuptreemaincontrol"&Seleccionar Tudo &Select Alltreemaincontrol,&Seleccione um exemplo&Select Sampletreemaincontrol&Seleccionar &Modelo&Select Templatetreemaincontrol&Filtro de &Texto...&Text Filter...treemaincontrolCpia de segurana {0} existente. Uma sesso anterior pode ter terminado inesperadamenteXg9"hD tm>.xE8l[m(%D0^&^0K7]48vH5(H5NU&VE)#c {TEO 5} e70KQVzP7~>'&x(F"* R*m*yy*`*`*%ao*Tأ*S*0a*5+5t +Ub+ +@ + u++U+:ܱ+į+cK/5)5S4&;0.xB,aDߠjWJlTaJJL L$$O($)RT uUw}VHWTXW:YYOZ8,7Zy%[[f3[f3p\`^#[^hzeceq7g}whz lwmDiwӴ{u}|US3lVt*=[`~1 c`c}MHq}u,$ fE;~:3P EJJVGUV#D IϋyOЄr~eBs`'51d:0S4c8Z]GA" Ye#/41X4FT!4M52{B"lE% H*aNLW*Oef`7sj.~uot}|{yޣ~s~B>tAwY(K/^o b6M‹XH/M ׽Rܷ*݊ Nrks:QuwUyd9}X=4[6veG{R5] _ [cgC x?<|>-yۇzBF%j+_/re0$~b 00&'~bҮt*<~CWJu1r /4:%r,B~tdUI~ SNt#.E1S969 @AD6NZXN$mR uXMv[óBaLnaM.f@g:i 5Slwpl-oFs͔zT}'~o.t[5$$^H_l[3WiZc Gw§#L2³:G=֓֓GƟ -bo^.T "AUb x5$Tf.Y<C%&=d(+(5}6a>?d@B Y@{iFJɢ\8y`}Clf4LgNe hT`phrkx]~3 }C`Tce'XP;G%]5OceN#RJ]BT[(N!.D-Yk+%Q"D"ϑĮeT4לR שD7+ؙ\Y:!KgkH`UFSW!m 5mNs t[Ѥ2cyL6~n;U #CW#C&$!y*F,D-.F/ //0?In3\LRSS"Zz Z]3_Pb#fe,JfR,fȊg%l?r^3yP9huNnl.ZYvIUTi29T~|ϥ<a9 .(.R(@ ˃Ψ/P7ieJ7xY_E0>|e|4)DYTL.&k?&tI(m3S)l/i0nd.7Oi8OiCdP[(^R9W]SU9Umt]1#hi=kUkN?=n`n}n*pk{U}\/n'Vo6 3_rN=Mu/&LJB [NvǨe˛DOeW"uE3v[ ^MhfOeųc. FP'Цa֤*Se?,0@A1cD$ 1cD.9H4@E6Fy LC#W9YJ[%%]!4bb n#DwƾQ.y {0>}SI ,9\ac %cIcc+)DHn&jT<©M*)mT9Ho<^! +3%%%%xḃ: E0%U^Ԥ?~޹U߂5ߗevx+^1mҷ $p  \~ \~ ;Ag q#5S - !"< 4E 5 :r F LGZ Mg f+>k] ky 7 d 8L  .4 ω6 \l bu b* ld ߡ K ]I _ , z ʵ6 tp n SG " q _4 cY  * .s |@ T  W?E ,_$9 /=V 4d 5r> 7* = ITh[ Ty Ul Wܾ@ _҉1 a cQ c e uo u5 = w5f ăf 5N 1Q 3 : I I I IJ I Iw Iװ Im Cz 8rw 9k + Z , 6"C 5X 08 >V ^ I( G = tH ˈ3= ĽN< ;: Gc, : : R ` ;T 5 e36 *K AW s .? ] ta X KM )M*W -8@ .2/ /.e 2 & 59 93C @(e At KsO K1U L.? L9A W X [thX f8 pI3x rWi x(! x( {ub :31 s  H *  @ Z= i]h F DU (u  ]w= Vv i{ D2F m B6 ~; ӣ tn Ae ٷX ߺ KGcw ~< \E- p ^( y~F C! v  cU EP M +K P'J %H #F Q loh k # '{ v (EOw *  2l,[ 7"5 8Ǒy ;yB =)V @|5" VA dMqq g#< pk_ t- t. t~ v" {B' { =T G eP h Mf- T} U 0R C_ 47 e h6 m)[ үY v bnj DD< U,f  Y  \ O e ' .] 0uX 0" 3 7yA CJ G9. H7G Kz9 KLC Mw Np> ]`^o _ | a*ǒ dT i= i$ i$ m. zJH ~D$ L 2ٹ  ݃ |K  =:B c2 DD ˜S˱ D V2 sW ~t > sS :nN fc"[ss^(t(-/+'0/h0>h9!= -Ej=H;AL`hLL?L^aV?YjZr]~EIhj"i?k lfcFXp#PTp#q t>t/CDE_^A82-ztĥgbt@:k}-`E )ԕxՁ_hYe89=hŲ %ItppVCR`ϰU;>bM EKcKRi(M6g8 qm<r@-HNIKMUZ8nA[K!^e36em3YiFWHrs$ww|*^}$7`?y4Aӝ\ԲA x]&ti2Ism}DQ,n#Hs\N.(u.$&| aɟ)Ҝ)~%]FoC/Tog9dU+y36f in&B<5=0&Cancelcolorset&OK&OKcolorset &25B D>=0 :=>?:8Button background colorcolorset$&25B H@8DB0 :=>?:8Button text colorcolorset 0AB@>9:0 &25B>2Color Settingscolorset&25B>20O "5<0 Color Themecolorset$&25B0 >;L7>20B5;O Custom Colorscolorset""5<0 ?>;L7>20B5;O Custom themecolorset"5<=0O B5<0 Dark themecolorset2"5<0 A8AB5<K ?> C<>;G0=8NDefault system themecolorset(&25B D>=0 8=B5@D59A0Dialog background colorcolorset,&25B H@8DB0 8=B5@D59A0Dialog text colorcolorset:&25B H@8DB0 =50:B82=>9 :=>?:8Disabled button text colorcolorset<&25B H@8DB0 =50:B82=>3> B5:AB0Disabled text foreground colorcolorset.&25B H@8DB0 38?5@AAK;:8Link text colorcolorset 01@0BL {0} F25BSelect {0} colorcolorset@&25B D>=0 2K1@0==>3> ?C=:B0 <5=NSelected item background colorcolorsetD&25B H@8DB0 2K1@0==>3> ?C=:B0 <5=NSelected item text colorcolorset<&25B D>=0 M;5<5=B>2 8=B5@D59A0Text widget background colorcolorsetN&25B D>=0 A8<2>;>2 M;5<5=B>2 8=B5@D59A0Text widget foreground colorcolorset&25B0 "5<K Theme Colorscolorset>&25B D>=0 2A?;K20NI59 ?>4A:07:8Tool tip background colorcolorsetP&25B D>=0 A8<2>;>2 2A?;K20NI59 ?>4A:07:8Tool tip foreground colorcolorset.&>1028BL >2>5 @028;> &Add New Rule conditional&B<5=0&Cancel conditional&0:@KBL&Close conditional&#40;8BL&Delete conditional,@5:@0B8BL &$8;LB@0F8N &End Filter conditionalB&D8;LB@>20BL&Filter conditional&03@C78BL&Load conditional&OK&OK conditional &#40;8BL @028;> &Remove Rule conditional&!>E@0=8BL&Save conditional>6LFalse conditional 09B8 &!;54CNI89 Find &Next conditional"09B8 &@54K4CI89Find &Previous conditional<O:Name: conditionalZ#4>2;5B2>@ONI85 CA;>28N A>2?045=8O =5 =0945=K!No conditional matches were found conditional"8? #7;0 Node Type conditional@028;> {0}Rule {0} conditional&!>E@0=5==K5 @028;0 Saved Rules conditional AB8=0True conditional[A5 "8?K] [All Types] conditional8and conditionalA>45@68Bcontains conditional>:0=G8205BAO =0 ends with conditional8;8or conditional=0G8=05BAO A starts with conditional&@8<5=8BL&Apply configdialog&B<5=0&Cancel configdialog"8? &0==KE &Data Type configdialog&#40;8BL "8? &Delete Type configdialog20A;54>20BL >B &8AB>G=8:0&Derive from original configdialog&K@065=85 &Equation configdialog0AB@>9:0 &>;O &Field Config configdialog"8? &>;O &Field Type configdialog@&!:@KBL >?>;=8B5;L=K5 0AB@>9:8&Hide Advanced configdialog"5@5<5AB8BL &=87 &Move Down configdialog&>2>5 >;5... &New Field... configdialog&>2K9 "8?... &New Type... configdialog&OK&OK configdialog&@8AB02:0&Prefix configdialog&!1@>A8BL&Reset configdialog&"8?  57C;LB0B0 &Result Type configdialogK1@0BL &A5 &Select All configdialogD>:070BL &>?>;=8B5;L=K5 0AB@>9:8&Show Advanced configdialog(@8B5@88 &!>@B8@>2:8&Sort Criteria configdialog"$>@<0B &03>;>2:0 &Title Format configdialogH>1028BL &?CABK5 AB@>:8 <564C C7;0<8Add &blank lines between nodes configdialog>1028BL >;5 Add Field configdialog>1028BL "8?Add Type configdialog@>1028BL 8;8 #40;8BL "8?K 0==KEAdd or Remove Data Types configdialog0>1028BL &<0@:5@K B5:AB0Add text bullet&s configdialogV#G8BK20BL ?@8 D>@<0B8@>20=88 &HTML-@07<5B:CAllow &HTML rich text in format configdialog0@8D<5B8G5A:85 ?5@0B>@KArithmetic Operators configdialog&2B><0B8G5A:85 "8?KAutomatic Types configdialog0!?8A>: >?CAB8<KE &>;59Available &Field List configdialog >?CAB8<K5 &>;OAvailable &Fields configdialogDB>3>2>5 =0G5=85 >38G5A:>3> "8?0Boolean Result configdialogt52>7<>6=> C40;8BL B8?, 2 C7;0E :>B>@>3> A>45@60BAO 40==K5+Cannot delete data type being used by nodes configdialog!<5=8BL &=0G>: Change &Icon configdialogB'8A;> >4AG8B0==KE >G5@=8E #7;>2 Child Count configdialog:!AK;:0 =0 >;5 >G5@=53> #7;0Child Reference configdialog>3@0=8G5=8O "8?0 >G5@=53> #7;0Child Type Limits configdialogG8AB8BL &K1>@ Clear &Select configdialog&!&:>?8@>20BL "8?... Co&py Type... configdialog~& 0745;8B5;L =0G5=89 "8?0 ><18=0F8O && !?8A:>2 >G5@=8E #7;>2+Combination && Child List Output &Separator configdialog&?5@0B>@K !@02=5=8OComparison Operators configdialog,0AB@>9:0 "8?>2 0==KEConfigure Data Types configdialog>?8@>20BL "8? Copy Type configdialog>4AG8B0BLCount configdialog,!>740BL #&A;>2=K5 "8?KCreate Co&nditional Types configdialogB>3>20O 0B0 Date Result configdialogL=0G5=85 ?> &#<>;G0=8N 4;O >2KE #7;>2Default &Value for New Nodes configdialog@"8? &>G5@=53> #7;0 ?> #<>;G0=8NDefault Child &Type configdialog 040BL K@065=85Define Equation configdialogJ040BL K@065=85 0B5<0B8G5A:>3> >;ODefine Math Field Equation configdialog&#40;8BL >;5 Dele&te Field configdialogF!45;0BL @>872>4=K< >B &1I53> "8?0Derived from &Generic Type configdialog?8A0=85 Description configdialog0?@02;5=85 Direction configdialog*KA>B0 >;O  540:B>@0 Editor Height configdialog02548B5 8<O =>2>3> ?>;O:Enter new field name: configdialog02548B5 8<O =>2>3> B8?0:Enter new type name: configdialog,H81:0 2 2K@065=88: {}Equation error: {} configdialogzH81:0  F8:;8G5A:0O AAK;:0 2 2K@065=8OE <0B5<0B8G5A:>3> ?>;O2Error - circular reference in math field equations configdialog*?@545;OBL B538 &HTMLEvaluate &HTML tags configdialog(>?>;=8B5;L=K9 "5:AB Extra Text configdialog &>;5F&ield configdialog!?8A>: &>;59 F&ield List configdialog>;5Field configdialog!?8A>: &>;59 Field &List configdialog!AK;:8 =0 >;5Field References configdialog8!AK;:0 =0 =D>@<0F8N > $09;5File Info Reference configdialog(!<5=8BL &0?@02;5=85Flip &Direction configdialog4!?@02:0 ?> &$>@<0B8@>20=8N Format &Help configdialog =0G>:Icon configdialog00B5<0B8G5A:>5 K@065=85 Math Equation configdialog,7<5=8BL !?8A>: &>;59Modify &Field List configdialog.7<5=8BL &#A;>2=K5 "8?KModify Co&nditional Types configdialog$5@5<5AB8BL &25@EMove &Up configdialog"5@5<5AB8BL &=87 Move Do&wn configdialog$5@5<5AB8BL &25@EMove U&p configdialog<OName configdialog8 >48=None configdialog&&'8A;> AB@>: B5:AB0Num&ber of text lines configdialogB>3>2>5 '8A;> Number Result configdialog('8A;> >G5@=8E #7;>2Number of Children configdialog"8? &?5@0B>@0O&perator Type configdialog &K2>4O&utput configdialog$!?8A>: &?5@0B>@>2Oper&ator List configdialog?5@0F88 Operations configdialog*!AK;:8 =0 @C385 >;OOther Field References configdialog$>@<0B &K2>40Out&put Format configdialog$>@<0B &K2>40Outpu&t Format configdialogK2>4 2 HTML Output HTML configdialog?F88 K2>40Output Options configdialogB!AK;:0 =0 >;O  >48B5;LA:>3> #7;0Parent Reference configdialog"8? &!AK;:8Refere&nce Type configdialog&#@>25=L !AK;:8Reference &Level configdialog&"8? !AK;:8Reference &Type configdialog&#@>25=L !AK;:8Reference Le&vel configdialog,5&@58<5=>20BL >;5...Rena&me Field... configdialog*&5@58<5=>20BL "8?...Rena&me Type... configdialog$5@58<5=>20BL >;5 Rename Field configdialog"5@58<5=>20BL "8? Rename Type configdialog,5@58<5=>20BL 87 {} 2:Rename from {} to: configdialog:!AK;:0 =0 >;5 >@=52>3> #7;0Root Reference configdialog$5 K1@0BL &8G53> Select &None configdialog4!AK;:0 =0 >;O !2>53> #7;0Self Reference configdialog807=0G8BL =0G>: "8?0 0==KESet Data Type Icon configdialogN07=0G8BL "8?K 2 7028A8<>AB8 >B #A;>289Set Types Conditionally configdialog(;NG8 &!>@B8@>2:8... Sort &Keys... configdialog;NG !>@B8@>2:8Sort Key configdialog*>;O ;NG0 !>@B8@>2:8Sort Key Fields configdialog&:>=G0=85Suffi&x configdialog!?8A>: &"8?>2 T&ype List configdialog&"5:AB>2K5 ?5@0B>@KText Operators configdialogB>3>2K9 "5:AB Text Result configdialogB!;54CNI85 A8<2>;K =54>?CAB8<K: {},The following characters are not allowed: {} configdialog0<O =5 <>65B 1KBL ?CABK<The name cannot be empty configdialog<<O =5 <>65B A>45@60BL ?@>15;KThe name cannot contain spaces configdialog><O =5 <>65B =0G8=0BLAO A "xml" The name cannot start with "xml" configdialog:<O 4>;6=> =0G8=0BLAO A 1C:2K!The name must start with a letter configdialog(<O C65 8A?>;L7>20=>The name was already used configdialogB>3>2>5 @5<O Time Result configdialog0AB@>9:0 &"8?0 Typ&e Config configdialog"8?Type configdialogJA?>;L7>20BL B01;8FC 4;O &40==KE ?>;OUse a table for field &data configdialog([A5 "8?K >?CAB8<K][All Types Available] configdialog&01A>;NB=>5 7=0G5=85absolute value configdialogA;>68BLadd configdialog0@::>A8=CA arc cosine configdialog0@:A8=CAarc sine configdialog0@:B0=35=A arc tangent configdialogA@54=55average configdialog&45AOB8G=K9 ;>30@8D<base-10 logarithm configdialog0AF5?8BL B5:AB>2K5 AB@>:8concatenate text configdialogH?@5>1@07>20BL B5:AB 2 =86=89 @538AB@convert text to lower case configdialogJ?@5>1@07>20BL B5:AB 2 25@E=89 @538AB@convert text to upper case configdialog$:>A8=CA 2 @0480=0Ecosine of radians configdialog"3@04CAK 2 @0480=Kdegrees to radians configdialog@0745;8BLdivide configdialog @02=>equal to configdialogD0:B>@80; factorial configdialog?;020NI0O B>G:0floating point configdialog*F5;>G8A;5==>5 45;5=85 floor divide configdialog 2?5@54forward configdialog>>fwd configdialog1>;LH5 G5< greater than configdialog 1>;LH5 8;8 @02=>greater than or equal to configdialog&1>;LH55 F5;>5 G8A;>higher integer configdialogh70<5=8BL 2 1-< 0@3C<5=B5 2-9 0@3C<5=B 3-< 0@3C<5=B><(in 1st arg, replace 2nd arg with 3rd arg configdialog?@8A>548=8BL B5:AB, 8A?>;L7CO 7=0G5=85 1-3> 0@3C<5=B0 2 :0G5AB25 @0745;8B5;O$join text using 1st arg as separator configdialog<5=LH5 G5< less than configdialog <5=LH5 8;8 @02=>less than or equal to configdialog;>38G5A:>5  logical and configdialog;>38G5A:>5  logical or configdialog&<5=LH55 F5;>5 G8A;> lower integer configdialog<0:A8<C<maximum configdialog<8=8<C<minimum configdialog <>4C;Lmodulus configdialogC<=>68BLmultiply configdialog@>A=>20=85 =0BC@0;L=>3> ;>30@8D<0natural log constant configdialog(=0BC@0;L=K9 ;>30@8D<natural logarithm configdialog=5 @02=> not equal to configdialogG8A;> ?8 pi constant configdialog$2>725AB8 2 AB5?5=Lpower configdialog"@0480=K 2 3@04CAKradians to degrees configdialog<<rev configdialog>A<5=8BL =0?@02;5=85 =0 >1@0B=>5reverse configdialog6>:@C3;8BL 4> G8A;0 @07@O4>2round to num digits configdialog A8=CA 2 @0480=0Esine of radians configdialog":204@0B=K9 :>@5=L square root configdialog2KG5ABLsubtract configdialogAC<<0 M;5<5=B>2 sum of items configdialog$B0=35=A 2 @0480=0Etangent of radians configdialogr8AB8=0, 5A;8 1-9 B5:AB>2K9 0@3C<5=B A>45@68B 2-9 0@3C<5=B%true if 1st text arg contains 2nd arg configdialog~8AB8=0, 5A;8 1-9 B5:AB>2K9 0@3C<5=B >:0=G8205BAO 2-< 0@3C<5=B><&true if 1st text arg ends with 2nd arg configdialogl8AB8=0, 5A;8 1-9 0@3C<5=B =0G8=05BAO A> 2-3> 0@3C<5=B0(true if 1st text arg starts with 2nd arg configdialogV8AB8==>5 7=0G5=85, CA;>285, ;>6=>5 7=0G5=85"true value, condition, false value configdialog*CA5G5==>5 F5;>5 G8A;>truncated integer configdialog&>8A: $09;0&Browse for File dataeditors&B<5=0&Cancel dataeditors&5@59B8 : &5;8 &Go to Target dataeditors&OK&OK dataeditors(&B:@KBL 8?5@AAK;:C &Open Link dataeditors(&B:@KBL 7>1@065=85 &Open Picture dataeditorsP;8:=8B5 =0 F5;52CN 38?5@AAK;:C 2 45@525(Click link target in tree) dataeditors1A>;NB=K9Absolute dataeditors 4@5AAddress dataeditors*G8AB8BL &8?5@AAK;:C Clear &Link dataeditors>:070BL <O Display Name dataeditors&=5H=OO 8?5@AAK;:0 External Link dataeditors.040BL "8? CB8 : $09;CFile Path Type dataeditors,=CB@5==OO 8?5@AAK;:0 Internal Link dataeditorsB:@KBL &0?:C Open &Folder dataeditors48?5@AAK;:0 =0 7>1@065=85 Picture Link dataeditorsB=>A8B5;L=K9Relative dataeditors!B@C:BC@0Scheme dataeditors8#AB0=>28BL &!53>4=OH=NN 0BC Set to &Now dataeditors"!53>4=OH=OO &0B0 Today's &Date dataeditorsLTreeLine  8?5@AAK;:0 =0 =5H=89 $09;TreeLine - External Link File dataeditors<TreeLine  $09; A 7>1@065=85<TreeLine - Picture File dataeditors38?5@AAK;:0link dataeditors&!B>;1FK&Columnsexports|"01;8F0 ?>B><:>2 (=><5@0 C@>2=59), @07<5G5==0O &70?OBK<8 (CSV);&Comma delimited (CSV) table of descendants (level numbers)exports&A5 5@52> &Entire treeexports &HTML&HTMLexports00:;04:8 2 D>@<0B5 &HTML&HTML format bookmarksexports.&:;NG8BL :>@=52K5 C7;K&Include root nodesexports!B@C:BC@0 &ODF &ODF Outlineexports>&!B0@0O 25@A8O Treeline (2.0.x)&Old TreeLine (2.0.x)exports<&">;L:> >B:@KBK5 4>G5@=85 C7;K&Only open node childrenexports048=>G=0O AB@0=8F0 &HTML&Single HTML pageexports@&"01C;8@>20==K9 B5:AB 703>;>2:>2&Tabbed title textexports &"5:AB&Textexports&>445@52> &TreeLine&TreeLine SubtreeexportsJ&5D>@<0B8@>20==K9 2K2>4 2A53> B5:AB0&Unformatted output of all textexports00:;04:8 2 D>@<0B5 &XBEL&XBEL format bookmarksexports$&XML (>1I53> 2840)&XML (generic)exports0&:;04:8 Book&marksexports0:;04:8 BookmarksexportsHK15@8B5 ?>4B8? D>@<0B0 4;O M:A?>@B0Choose export format subtypeexportsBK15@8B5 B8? D>@<0B0 4;O M:A?>@B0Choose export format typeexports6K15@8B5 =0AB@>9:8 M:A?>@B0Choose export optionsexports"01;8F0 4>G5@=8E C7;>2, @07<5G5==0O &70?OBK<8 (CSV) (548=AB25==K9 C@>25=L)7Comma &delimited (CSV) table of children (single level)exportsH81:0  =52>7<>6=> CAB0=>28BL AAK;:C =0 =5A>E@0=5==K9 D09; Treeline. !>E@0=8B5 D09; 8 ?>?@>1C9B5 A=>20.FError - cannot link to unsaved TreeLine file. Save the file and retry.exports-:A?>@B $09;0 File ExportexportsN&:;NG8BL 25@E=89 && =86=89 :>;>=B8BC;KInclude &print header && footerexports=B5@0:B82=K9 ?@>A<>B@ 45@520, ?@82O70==>3> : D09;C Treeline (4;O 251-A5@25@0)8Live tree view, linked to TreeLine file (for web server)exports=B5@0:B82=K9 ?@>A<>B@ 45@520, >48=>G=K9 D09; (2AB@>5==K5 40==K5)+Live tree view, single file (embedded data)exportsP=>3>AB@0=8G=K9 HTML A B01;8F0<8 &40==KEMultiple HTML &data tablesexportsR=>3>AB@0=8G=K9 &HTML A ?0=5;LN =02830F88)Multiple HTML &pages with navigation paneexportsP5@54 M:A?>@B>< 4>;6=K 1KBL 2K1@0=K C7;K!Must select nodes prior to exportexports8&#@>2=8 =02830F8>==>9 ?0=5;8Navigation pane &levelsexports @C385 0AB@>9:8 Other Optionsexports >48B5;LParentexports K1@0==K5 &25B28Selected &branchesexportsK1@0==K5 &C7;KSelected &nodesexportsX48=>G=0O AB@0=8F0 &HTML A ?0=5;LN =02830F88&Single &HTML page with navigation paneexports~"01;8F0 4>G5@=8E C7;>2, @07<5G5==0O Tab (&548=AB25==K9 C@>25=L)0Tab &delimited table of children (&single level)exportsTree&Line Tree&LineexportsHTreeLine  -:A?>@B 2 XML 1I53> 840TreeLine - Export Generic XMLexports2TreeLine  -:A?>@B 2 HTMLTreeLine - Export HTMLexportsDTreeLine  -:A?>@B 2 0:;04:8 HTML TreeLine - Export HTML Bookmarksexports<TreeLine  -:A?>@B 2 ODF "5:ABTreeLine - Export ODF TextexportsDTreeLine  -:A?>@B 2 @>AB>9 "5:ABTreeLine - Export Plain TextexportsLTreeLine  -:A?>@B 2 "5:AB>2K5 "01;8FKTreeLine - Export Text TablesexportsHTreeLine  -:A?>@B 03>;>2:>2 "5:AB0TreeLine - Export Text TitlesexportsNTreeLine  -:A?>@B 2 >445@52> Treeline"TreeLine - Export TreeLine SubtreeexportsDTreeLine  -:A?>@B 2 0:;04:8 XBEL TreeLine - Export XBEL Bookmarksexports=8<0=85  >BACBAB2C5B >B=>A8B5;L=K9 ?CBL >B{0} : {1}. @>4>;68BL, 8A?>;L7CO 01A>;NB=K9 ?CBL?LWarning - no relative path from "{0}" to "{1}". Continue with absolute path?exports$'B> -:A?>@B8@>20BLWhat to Exportexports"." !8<2>; .."." Character .. fieldformat"/" !8<2>; //"/" Character // fieldformat 0 ;8 1 >2B>@ ?0 Or 1 Repetitions ? fieldformat,0 ;8 >;55 >2B>@>2 *0 Or More Repetitions * fieldformat,1 ;8 >;55 >2B>@>2 +1 Or More Repetitions + fieldformat AM/PMAM/PM %p fieldformatN1>9 !8<2>; .Any Character . fieldformat2B>K1>@ AutoChoice fieldformat2B>><18=0F8OAutoCombination fieldformat>38G5A:89 "8?Boolean fieldformat"03;02=0O C:20 ACapital Letter A fieldformat203;02=0O  8<A:0O &8D@0 ICapital Roman Numeral I fieldformat K1>@Choice fieldformat><18=0F8O Combination fieldformat, 0745;8B5;L 0?OB0O \,Comma Separator \, fieldformat0B0Date fieldformat0B0 8 @5<ODateTime fieldformat05=L (1 8;8 2 F8D@K) %-dDay (1 or 2 digits) %-d fieldformat"5=L (2 F8D@K) %dDay (2 digits) %d fieldformat65=L >40 (>B 1 4> 366) %-jDay of year (1 to 366) %-j fieldformat(5AOB8G=0O 0?OB0O ,Decimal Comma , fieldformat$5AOB8G=0O ">G:0 .Decimal Point . fieldformat >4AG5B >B><:>2DescendantCount fieldformatF&8D@0 8;8 @>15; (2=5H=89) <space>!Digit or Space (external)  fieldformat6 0745;8B5;L 2 2845 ">G:8 \.Dot Separator \. fieldformat>=5F !B@>:8 $ End of Text $ fieldformatH-:@0=8@>20=85 !?5F80;L=>3> !8<2>;0 \Escape a Special Character \ fieldformat1@075F 1/2/3/4Example 1/2/3/4 fieldformat:A=>20=85 AB5?5=8 (1>;LH>5) EExponent (capital) E fieldformat6A=>20=85 AB5?5=8 (<0;>5) eExponent (small) e fieldformat&=5H=OO 8?5@AAK;:0 ExternalLink fieldformat8'0A (0-23, 1 8;8 2 F8D@K) %HHour (0-23, 1 or 2 digits) %-H fieldformat.'0A (00-23, 2 F8D@K) %HHour (00-23, 2 digits) %H fieldformat.'0A (01-12, 2 F8D@K) %IHour (01-12, 2 digits) %I fieldformat:'0A (1-12, 1 8;8 2 F8D@K) %-IHour (1-12, 1 or 2 digits) %-I fieldformat,"5:AB A @07<5B:>9 HTMLHtmlText fieldformat,=CB@5==OO 8?5@AAK;:0 InternalLink fieldformat* 0745;8B5;L #@>2=59 /Level Separator / fieldformat:C:2K 2 86=5<  538AB@5 [0-O]Lower Case Letters [a-z] fieldformat&0B5<0B8G5A:>5 >;5Math fieldformat08:@>A5:C=40 (6 F8D@) %fMicroseconds (6 digits) %f fieldformat48=CB0 (1 8;8 2 F8D@K) %-MMinute (1 or 2 digits) %-M fieldformat&8=CB0 (2 F8D@K) %MMinute (2 digits) %M fieldformat25AOF (1 8;8 2 F8D@K) %-mMonth (1 or 2 digits) %-m fieldformat$5AOF (2 F8D@K) %mMonth (2 digits) %m fieldformat<!>:@0I5==>5 0720=85 5AOF0 %bMonth Abbreviation %b fieldformat$0720=85 5AOF0 %B Month Name %B fieldformat5 &8D@0 [^0-9]Not a Number [^0-9] fieldformat !53>4=O 8 !59G0ANow fieldformat '8A;>Number fieldformat><5@ 1Number 1 fieldformatC<5@0F8O Numbering fieldformat$4=>AB@>G=K9 "5:AB OneLineText fieldformat,5>1O70B5;L=0O &8D@0 #Optional Digit # fieldformat*5>1O70B5;L=K9 =0: -Optional Sign - fieldformat  |Or | fieldformat@1@075F 0:5B0 I../A../1../a)/i)!Outline Example I../A../1../a)/i) fieldformat7>1@065=85Picture fieldformat( 53C;O@=>5 K@065=85RegularExpression fieldformat(1O70B5;L=0O &8D@0 0Required Digit 0 fieldformat$5>1E>48<K9 =0: +Required Sign + fieldformat6!5:C=40 (1 8;8 2 F8D@K) %-SSecond (1 or 2 digits) %-S fieldformat(!5:C=4a (2 F8D@K) %SSecond (2 digits) %S fieldformat.1@075F  0745;0 1.1.1.1Section Example 1.1.1.1 fieldformat, 0745;8B5;L  0745;>2 .Section Separator . fieldformat 0745;8B5;L / Separator / fieldformat 01>@ &8D@ [0-9]Set of Numbers [0-9] fieldformat !B@>G=0O 1C:20 aSmall Letter a fieldformat0!B@>G=0O  8<A:0O &8D@0 iSmall Roman Numeral i fieldformatV@>15;L=K9  0745;8B5;L (2=CB@5==89) <space>"Space Separator (internal)  fieldformatD"5:AB A 564CAB@>G=K<8 =B5@20;0<8 SpacedText fieldformat/T/F fieldformat "5:ABText fieldformat @5<OTime fieldformat<C:2K 2 5@E=5<  538AB@5 [-/]Upper Case Letters [A-Z] fieldformat:><5@ 545;8 (>B 0 4> 53) %-UWeek Number (0 to 53) %-U fieldformatD!>:@0I5==>5 0720=85 =O 545;8 %aWeekday Abbreviation %a fieldformat5=L 545;8 %AWeekday Name %A fieldformat/Y/N fieldformat >4 (2 F8D@K) %yYear (2 digits) %y fieldformat >4 (4 F8D@K) %YYear (4 digits) %Y fieldformat8AB8=0/;>6L true/false fieldformat 40/=5Byes/no fieldformat;>6Lfalse genboolean=5Bno genboolean 8AB8=0true genboolean40yes genbooleanA5 $09;K All Files globalref$A5 $09;K TreelineAll TreeLine Files globalref<$09;K CSV ( 07<5G5=K 0?OBK<8)CSV (Comma Delimited) Files globalref$09;K HTML HTML Files globalref$09;K ODFODF Text Files globalref8$09;K !B0@>9 5@A88 TreeLineOld TreeLine Files globalref$09;K PDF PDF Files globalref"5:AB>2K5 $09;K Text Files globalref$09;K TreeLineTreeLine Files globalref,$09;K TreeLine  !60BKTreeLine Files - Compressed globalref8$09;K TreeLine  0H8D@>20=KTreeLine Files - Encrypted globalref$09;K Treepad Treepad Files globalref$09;K XML XML Files globalref 09B8: Find: helpview &0704&Backhelpview&?5@54&Forwardhelpview& 0G0;C&Homehelpview &09B8 !;54CNI89 Find &Nexthelpview"09B8 &@54K4CI89Find &Previoushelpview6"5:AB>20O AB@>:0 =5 =0945=0Text string not foundhelpview=AB@C<5=BKToolshelpview"{0}" =5 O2;O2;O5BAO D09;><, ?>4E>4OI8< 4;O Treeline. @8<5=8BL D8;LB@ 4;O 8<?>@B0?:"{0}" is not a valid TreeLine file. Use an import filter?importsFXML &1I53> 840 (=5 D09; Treeline) &Generic XML (non-TreeLine file)importsD0:;04:8 &HTML (2 D>@<0B5 Mozilla) &HTML bookmarks (Mozilla Format)importsV"5:AB A &Tab->BABC?0<8, >48= C75; =0 AB@>:C%&Tab indented text, one node per lineimports<0:;04:8 &XML (2 D>@<0B5 XBEL)&XML bookmarks (XBEL format)importsBOOKMARKimports@525@=K9 D>@<0B CSV 2 AB@>:5 {0}Bad CSV format on Line {0}imports0:;04:8 Bookmarksimports<K15@8B5 !?>A>1 <?>@B8@>20=8OChoose Import Methodimports"5:AB>20O B01;8F0, @07<5G5==0O 70&?OBK<8 (CSV), A> AB>;1F>< C@>2=59 && AB@>:>9 703>;>2:0ACo&mma delimited (CSV) text table with level column && header rowimports"5:AB>20O B01;8F0, @07<5G5==0O 70&?OBK<8 (CSV) A> AB@>:>9 703>;>2:01Comma delimited (CSV) text table &with header rowimportsLH81:0  =52>7<>6=> ?@>G8B0BL D09; {0}Error - could not read file {0}imports<H81:0  =525@=K9 D>@<0B 2 {0}Error - improper format in {0}imports FOLDERimports$<?>@B8@>20BL $09; Import Fileimports525@=K9 $09; Invalid FileimportsD525@=K9 =><5@ C@>2=O 2 AB@>:5 {0} Invalid level number on line {0}imports2525@=0O AB@C:BC@0 C@>2=OInvalid level structureimports8?5@AAK;:0LinkimportsT$09; Tree&Line !B0@>9 5@A88 (1.x 8;8 2.x)Old Tree&Line File (1.x or 2.x)importsDB:@KBL !B@C:BC@C &>:C<5=B0 (ODF)Open &Document (ODF) outlineimports @C385Otherimportsr&@>AB>9 B5:AB A 0170F0<8 (@073@0=8G5=K ?CABK<8 AB@>:0<8)-Plain text ¶graphs (blank line delimited)imports@>AB>9 B5:AB, >48= &C75; =0 AB@>:C (>3@0=8G5==K9 ?5@5=>A>< AB@>:8)-Plain text, one &node per line (CR delimited)imports ", SEPARATORimports"&TABLEimportsr"5:AB>20O B01;8F0, @07<5G5==0O Tab, A> AB&@>:>9 703>;>2:0)Tab delimited text table with header &rowimports "5:ABTextimportsH!;8H:>< <=>3> M;5<5=B>2 2 !B@>:5 {0}Too many entries on Line {0}imports:TreeLine  <?>@B8@>20BL $09;TreeLine - Import FileimportsJ&$09; Treepad (B>;L:> B5:AB>2K5 C7;K)Treepad &file (text nodes only)importsl!AK;:8 =0 4>G5@=85 C7;K 4>;6=K 1KBL 2:;NG5=K 2 DC=:F8N/Child references must be combined in a functionmatheval254>?CAB8<K5 "{}" A8<2>;KIllegal "{}" charactersmatheval254>?CAB8<0O DC=:F8O: {0}Illegal function present: {0}mathevalT54>?CAB8<K9 B8? >1J5:B0 8;8 >?5@0B>@: {0}$Illegal object type or operator: {0}mathevalD54>?CAB8<K9 A8=B0:A8A 2 2K@065=88Illegal syntax in equationmatheval4525@=K5 <>48D8:0B>@K ?>;OInvalid field modifiersmatheval&@8<5=8BL&Apply miscdialogs&B<5=0&Cancel miscdialogs&0:@KBL&Close miscdialogs,&@5:@0B8BL $8;LB@0F8N &End Filter miscdialogsA5 &45@52> &Entire tree miscdialogs&$8;LB@>20BL&Filter miscdialogs 09B8 &!;54CNI89 &Find Next miscdialogs&?5@54&Forward miscdialogs4&3=>@8@>20BL 8 ?@>?CAB8BL&Ignore and skip miscdialogs&;NG52K5 A;>20 &Key words miscdialogs"8? &#7;0 &Node Type miscdialogs&OK&OK miscdialogs>&@54>?@545;5==K5 ;NG52K5 >;O&Predefined Key Fields miscdialogs*& 53C;O@=>5 2K@065=85&Regular expression miscdialogs&0<5=8BL&Replace miscdialogs&5@570?CAB8BL =C<5@0F8N A =0G0;0 4;O A;54CNI8E A5AB@8=A:8E C7;>2"&Restart numbers for next siblings miscdialogsF>AAB0=>28BL =0G5=8O ?> &#<>;G0=8N&Restore Defaults miscdialogs(&!<5=8BL =0?@02;5=85&Reverse miscdialogs&A:><K9 "5:AB &Search Text miscdialogs4&>G5@=85 C7;K 2 2K1@0==><&Selection's children miscdialogs(">;L:> 2 &703>;>2:0E &Titles only miscdialogs(&0=5;8 =AB@C<5=B>2 &Toolbars miscdialogsD&1@010BK20BL ?CABK5 ?>;O :0: =C;8&Treat blank fields as zeros miscdialogsV&A?>;L7>20BL H@8DB ?@8;>65=8O ?> C<>;G0=8N&Use app default font miscdialogs0@8<5=8BL A&60B85 D09;>2&Use file compression miscdialogsTA?>;L7>20BL &A8AB5<=K9 H@8DB ?> C<>;G0=8N&Use system default font miscdialogs-- 0745;8B5;L-- --Separator-- miscdialogs&>&?CAB8<K5 ><0=4KA&vailable Commands miscdialogs"N1>5 &A>2?045=85 Any &match miscdialogs:(@8DB @8;>65=8O ?> #<>;G0=8NApp Default Font miscdialogsG8AB8BL &;NG Clear &Key miscdialogs 0AB@>8BL (@8DBKCustomize Fonts miscdialogs:0AB@>8BL 0=5;8 =AB@C<5=B>2Customize Toolbars miscdialogs 0==K5Data miscdialogs5=N 0==K5 Data Menu miscdialogsB> #<>;G0=8N  4=>AB@>G=K9 "5:ABDefault - Single Line Text miscdialogs 540:B8@>20BLEdit miscdialogs5=N @02:0 Edit Menu miscdialogs(@8DB  540:B>@0Editor View Font miscdialogs:0@>;L : 0H8D@>20==><C $09;CEncrypted File Password miscdialogsLH81:0  =525@=>5 @53C;O@=>5 2K@065=85"Error - invalid regular expression miscdialogs4H81:0  70<5=0 =52>7<>6=0Error - replacement failed miscdialogs">;=>5 &2K@065=85 F&ull phrase miscdialogs>;OFields miscdialogs$09;File miscdialogs5=N $09; File Menu miscdialogs!2>9AB20 $09;0File Properties miscdialogs$$09;>2>5 %@0=8;8I5 File Storage miscdialogs$8;LB@>20BLFilter miscdialogs >8A:Find miscdialogs 09B8 &!;54CNI89 Find &Next miscdialogs"09B8 &@54K4CI89Find &Previous miscdialogs>8A: 8 0<5=0Find and Replace miscdialogs$>@<0B8@>20BLFormat miscdialogs5=N $>@<0B Format Menu miscdialogs> 2A5E &40==KE Full &data miscdialogs&5;K5 &A;>20 Full &words miscdialogsF1@01>B:0 #7;>2 157 >;59 C<5@0F88'Handling Nodes without Numbering Fields miscdialogs!?@02:0Help miscdialogs5=N !?@02:8 Help Menu miscdialogs0: A:0BL How to Search miscdialogs::;NG8BL C7;K 25@E=8E C@>2=59Include top-level nodes miscdialogs,>;=K5 :;NG52K5 &A;>20Key full &words miscdialogs2;NG {0} C65 8A?>;L7C5BAOKey {0} is already used miscdialogs>@OG85 ;028H8Keyboard Shortcuts miscdialogs>;LH85 =0G:8 Large Icons miscdialogs&0B5<0B8G5A:85 >;O Math Fields miscdialogs"5@5<5AB8BL &=87 Move &Down miscdialogs$5@5<5AB8BL &25@EMove &Up miscdialogs>;O &#7;>2 N&ode Fields miscdialogs 5=N >BACBAB2C5BNo menu miscdialogsP>;O =C<5@0F88 2 B8?0E 40==KE =5 =0945=K,No numbering fields were found in data types miscdialogs#75;Node miscdialogs &03>;>2:8 #7;>2 Node &Titles miscdialogs5=N #75; Node Menu miscdialogs((@8DB 2 $>@<5 K2>40Output View Font miscdialogs* 5&3C;O@=>5 2K@065=85Re&gular expression miscdialogs,2548B5 0@>;L 0=>2>:Re-Type Password: miscdialogsD=>2L =01@0==K9 ?0@>;L =5 ?>4E>48BRe-typed password did not match miscdialogs>0?><=8BL ?0@>;L B5:CI59 A5AA88%Remember password during this session miscdialogs0<5=8BL &A5 Replace &All miscdialogs.0<5=5=> {0} A>2?045=89Replaced {0} matches miscdialogs"0<5=ONI89 &"5:ABReplacement &Text miscdialogs.0&@575@28@>20BL =><5@0Reserve &numbers miscdialogs>@=52>9 #75; Root Node miscdialogs>A:><0O AB@>:0 "{0}" =5 =0945=0Search string "{0}" not found miscdialogs:A:><K9 B5:AB "{0}" =5 =0945=Search text "{0}" not found miscdialogs K1@0==K5 &25B28Selected &branches miscdialogs:&!5AB@8=A:85 C7;K 2 2K1@0==><Selection's &siblings miscdialogs4&>G5@=85 C7;K 2 2K1@0==><Selection's childre&n miscdialogs 0;5=L:85 =0G:8 Small Icons miscdialogs,0?@02;5=85 !>@B8@>2:8Sort Direction miscdialogs"!?>A>1 !>@B8@>2:8 Sort Method miscdialogs!>@B8@>20BL#7;K Sort Nodes miscdialogs*@>25@:0 @02>?8A0=8O Spell Check miscdialogs8><0=4K &0=5;8 =AB@C<5=B>2Tool&bar Commands miscdialogs6& 07<5@ 0=5;8 =AB@C<5=B>2 Toolbar &Size miscdialogs>>;8G5AB2> 0=5;59 =AB@C<5=B>2Toolbar Quantity miscdialogs=AB@C<5=BKTools miscdialogs 5=N =AB@C<5=BK Tools Menu miscdialogs2(8DB 4;O @>A<>B@0 5@520Tree View Font miscdialogs6TreeLine  !5@L57=0O H81:0TreeLine - Serious Error miscdialogs$C<5@0F8O TreeLineTreeLine Numbering miscdialogs22548B5 0@>;L 4;O "{0}":Type Password for "{0}": miscdialogs2548B5 0@>;L:Type Password: miscdialogs01=>28BL C<5@0F8N #7;>2Update Node Numbering miscdialogs8@8<5=8BL &H8D@>20=85 D09;>2Use file &encryption miscdialogs84View miscdialogs5=N 84 View Menu miscdialogs '5< A:0BLWhat to Search miscdialogs'B> !>@B8@>20BL What to Sort miscdialogs'B> 1=>2;OBLWhat to Update miscdialogs:=>Window miscdialogs5=N :=> Window Menu miscdialogsB0@>;8 =C;52>9 4;8=K =5 4>?CAB8<K'Zero-length passwords are not permitted miscdialogs[A5 >;O] [All Fields] miscdialogs[A5 "8?K] [All Types] miscdialogs<OName nodeformatl:B828@>20BL ?>;O @540:B>@0 40==KE ?@8 =02545=88 <KHLN$Activate data editors on mouse hoveroptiondefaults84 Appearanceoptiondefaults2B>!>E@0=5=85 Auto SaveoptiondefaultsL2B><0B8G5A:8 >B:@K20BL ?>A;54=89 D09;!Automatically open last file usedoptiondefaultsF5@58<5=>2K20BL C7;K ?> I5;G:C <KH8Click node to renameoptiondefaults0$>@<0BK  540:B>@0 0==KEData Editor Formatsoptiondefaults0B0Datesoptiondefaults">ABC?=K5 $C=:F88Features AvailableoptiondefaultsOB=8F0Fridayoptiondefaultsp!<5I0BL 2?@02> (4;O :@0A82>9 ?5G0B8) JSON D09;K Treeline)Indent (pretty print) TreeLine JSON filesoptiondefaults`3@0=8G8BL 2KA>BC @540:B>@0 40==KE @07<5@>< >:=0'Limit data editor height to window sizeoptiondefaultsP!2>@0G820BL ?@8;>65=85 2 A8AB5<=K9 ;>B>:#Minimize application to system trayoptiondefaults>;8G5AB2> <8=CB <564C A>E@0=5=8O<8 (CAB0=>28B5 0 4;O >B:;NG5=8O)+Minutes between saves (set to 0 to disable)optiondefaults>=545;L=8:MondayoptiondefaultsL'8A;> ?>A;54=8E D09;>2 2 D09;>2>< <5=N(Number of recent files in the file menuoptiondefaults<'8A;> 2>7<>6=KE >B<5= 459AB289Number of undo levelsoptiondefaults:B:@K20BL D09;K 2 =>2KE >:=0EOpen files in new windowsoptiondefaults >A;54=85 $09;K  Recent Filesoptiondefaultsj#40;OBL =54>ABC?=K5 40==K5, 2>H54H85 2 ?>A;54=89 D09;'Remove inaccessible recent file entriesoptiondefaultsX 540:B8@>20BL 8<5=0 =>2KE C7;>2 ?@8 A>740=88Rename new nodes when createdoptiondefaultsT>AAB0=02;820BL CAB0=>2:8 >:=0 ?@8 70?CA:5 Restore previous window geometryoptiondefaultsT>AAB0=02;820BL A>AB>O=85 ?>A;54=53> D09;0(Restore tree view states of recent filesoptiondefaults!C11>B0Saturdayoptiondefaults`:;NG8BL ?@>A<>B@ =02830F8>==>9 F5?>G:8 : ?@54:CShow breadcrumb ancestor viewoptiondefaults^>:07K20BL ?0=5;L 4>G5@=53> C7;0 2 D>@<5 A?@020#Show child pane in right hand viewsoptiondefaultsB>:07K20BL ?>B><:>2 2 >:=5 2K2>40Show descendants in output viewoptiondefaults4>:07K20BL 7=0G:8 2 45@525Show icons in the tree viewoptiondefaultsb>:07K20BL <0B5<0B8G5A:85 ?>;O 2  540:B>@5 0==KE&Show math fields in the Data Edit viewoptiondefaultsX>:07K20BL ?>;O =C<5@0F88 2  540:B>@5 0==KE+Show numbering fields in the Data Edit viewoptiondefaults2#A;>28O 0?CA:0 @>3@0<<KStartup Conditionoptiondefaults>A:@5A5=L5Sundayoptiondefaults'5B25@3Thursdayoptiondefaults @5<OTimesoptiondefaults^ 07@5H8BL ?5@5B0A:820=85 M;5<5=B>2 45@520 <KHLNTree drag && drop availableoptiondefaultsB>@=8:Tuesdayoptiondefaults8!>E@0=OBL 4;O >AAB0=>2;5=8O Undo Memoryoptiondefaults !@540 Wednesdayoptiondefaults&B<5=0&Canceloptions&OK&OKoptionsPK15@8B5 @0A?>;>65=85 D09;0 :>=D83C@0F88"Choose configuration file locationoptionsj8@5:B>@8O ?@>3@0<<K (4;O ?>@B0B82=>3> 8A?>;L7>20=8O)$Program directory (for portable use)options`><0H=OO 48@5:B>@8O ?>;L7>20B5;O (@5:><5=4C5BAO)#User's home directory (recommended)options:H81:0 8=8F80;870F88 ?@8=B5@0Error initializing printer printdata0TreeLine  -:A?>@B 2 PDFTreeLine - Export PDF printdata&!=87C:&Bottom: printdialogs&B<5=0&Cancel printdialogsB&B>1@060BL ?CB8 : 4>G5@=8< C7;0<&Draw lines to children printdialogs&A5 5@52> &Entire tree printdialogs &(@8DB&Font printdialogs&K1>@ (@8DB0&Font Selection printdialogs &1I85 0AB@>9:8&General Options printdialogs5@E=89 !&;520 &Header Left printdialogs4&5@E=89/86=89 >;>=B8BC;&Header/Footer printdialogs.&:;NG8BL :>@=52>9 C75;&Include root node printdialogsX>&:07K20BL ?5@2K9 4>G5@=89 C75; A @>48B5;5<&Keep first child with parent printdialogs!&;520:&Left: printdialogs&'8A;> AB>;1F>2&Number of columns printdialogs&OK&OK printdialogs&@8AB02:0&Prefix printdialogs&5G0BL... &Print... printdialogs!&?@020:&Right: printdialogs&:>=G0=85&Suffix printdialogs&!25@EC:&Top: printdialogs$&48=8FK 7<5@5=8O&Units printdialogsR&A?>;L7>20BL H@8DB D>@<K 2K2>40 TreeLine&Use TreeLine output view font printdialogs&(8@8=0:&Width: printdialogs"A3 (279 420 <<)A3 (279 x 420 mm) printdialogs"A4 (210 297 <<)A4 (210 x 297 mm) printdialogs"A5 (148 210 <<)A5 (148 x 210 mm) printdialogs>0123456...&F(H)I,L-M.N/OAaBbCcDdEeFfGg...TtUuVvWvXxYyZz printdialogs!0=B8<5B@K (A<)Centimeters (cm) printdialogs!B>;1FKColumns printdialogs040==K9  07<5@ Custom Size printdialogs$(@8DB ?> #<>;G0=8N Default Font printdialogsPH81:0:  07<5@ 8;8 ?>;O AB@0=8FK =525@=K(Error: Page size or margins are invalid printdialogs(>?>;=8B5;L=K9 B5:AB Extra Text printdialogs(!B@0=8FK 2  072>@>B5 Facing Pages printdialogs!2>9AB20Features printdialogs >&;OFiel&ds printdialogs&>;5 $>@<0B0 Field For&mat printdialogs*$>@<0B ?>;O 4;O "{0}"Field Format for "{0}" printdialogs !B@0=8F0 &5;8:><Fit Page printdialogs&0?>;=8BL ?> (8@8=5 Fit Width printdialogs$&0G5@B0=85 (@8DB0 Font st&yle printdialogs&86=89 &>;>=B8BC;:Foot&er: printdialogs86=89 &!;520 Footer &Left printdialogs"86=89 ?> &&5=B@CFooter Ce&nter printdialogs86=89 !&?@020 Footer Righ&t printdialogs4&!?@02:0 ?> $>@<0B8@>20=8N Format &Help printdialogs(&5@E=89 >;>=B8BC;:He&ader: printdialogs5@E=89 !&?@020 Header &Right printdialogs$5@E=89 ?> &&5=B@CHeader C&enter printdialogs85@E=89 8 86=89 >;>=B8BC;KHeader and Footer printdialogsKA>B0:Height: printdialogsN9<K (in.) Inches (in) printdialogs:;NG5==K5 #7;KIncluded Nodes printdialogs BABC?Indent printdialogs&;L1><=0O Lan&dscape printdialogs*Legal (8.5 14 Inch)Legal (8.5 x 14 in.) printdialogs,Letter (8.5 11 Inch)Letter (8.5 x 11 in.) printdialogs>;OMargins printdialogs8;;8<5B@K (<<)Millimeters (mm) printdialogs$!;54CNI0O !B@0=8F0 Next Page printdialogs<">&;L:> >B:@KBK5 4>G5@=85 C7;KOnl&y open node children printdialogs@85=B0F8O Orientation printdialogs&$>@<0B K2>40Output &Format printdialogs&&0@0<5B@K !B@0=8FK Page &Setup printdialogs& 07<5@ C<038 Paper &Size printdialogs&=86=0O Portra&it printdialogs&@54K4CI0O !B@0=8F0 Previous Page printdialogs 5G0BLPrint printdialogsF@5420@8B5;L=K9 @>&A<>B@ 5G0B8...Print Pre&view... printdialogs>@5420@8B5;L=K9 @>A<>B@ 5G0B8 Print Preview printdialogs 0AB@>9:0 5G0B8 Print Setup printdialogs 0AB@>9:0 5G0B8Printing Setup printdialogs @8<5@Sample printdialogs"K15@8B5 &@8=B5@Select &Printer printdialogsK15@8B5 (@8DB Select Font printdialogs K1@0==K5 &25B28Selected &branches printdialogsK1@0==K5 &C7;KSelected &nodes printdialogs &07<5@Si&ze printdialogs&4=8=>G=0O !B@0=8F0 Single Page printdialogs6 0AAB>O=85 <564C A&B>;1F0<8Space between colu&mns printdialogs,Tabloid (11 17 Inch)Tabloid (11 x 17 in.) printdialogs(PDF @8=B5@ TreeLineTreeLine PDF Printer printdialogs'B> ?5G0B0BL What to print printdialogs#25;8G8BLZoom In printdialogs#<5=LH8BLZoom Out printdialogs&>1028BL&Add spellcheck&B<5=0&Cancel spellcheck"3=>@8@>20BL &A5 &Ignore All spellcheck&0<5=8BL&Replace spellcheck6>1028BL 2 &86=5< @538AB@5Add &Lowercase spellcheck>=B5:AB:Context: spellcheck52>7<>6=> =09B8 =8 aspell.exe, =8 ispell.exe 8;8 hunspell.exe K1@0BL <5AB>@0A?>;>65=85?QCould not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? spellcheckr@>25@:0 ?@02>?8A0=8O 2 25B28 >:>=G5=0 @>4>;68BL A25@EC?3Finished checking the branch Continue from the top? spellcheck<@>25@:0 ?@02>?8A0=8O >:>=G5=0Finished spell checking spellcheck&3=>@8@>20BLIgnor&e spellcheck#:068B5 <5AB>@0A?>;>65=85 aspell.exe, ispell.exe 8;8 hunspell.exe-Locate aspell.exe, ipsell.exe or hunspell.exe spellcheck5B 2 !;>20@5Not in Dictionary spellcheck"@>3@0<<0 (*.exe)Program (*.exe) spellcheck0<5=8BL &A5 Re&place All spellcheck*@>25@:0 @02>?8A0=8O Spell Check spellcheck8H81:0 @>25@:8 @02>?8A0=8OSpell Check Error spellcheck@54;>65=8O Suggestions spellcheck<@>25@:0 @02>?8A0=8O TreeLineTreeLine Spell Check spellcheckH81:0 @>25@:8 @02>?8A0=8O TreeLine #4>AB>25@LB5AL, GB> aspell, ispell 8;8 hunspell CAB0=>2;5=LTreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed spellcheck !;>2>:Word: spellcheck K1@0BL 2 5@525Select in Tree titlelistview0@:5@KBullets treeformats>G5@=89"8? ChildType treeformats03@0=8G5=85>G5@=53>"8?0ChildTypeLimit treeformats#A;>2=>5@028;>ConditionalRule treeformats #'.DEFAULT treeformats?@54HTMLEvalHtml treeformatsFIELD treeformats$FILE treeformats"8? >;O FieldType treeformats $>@<0BFormat treeformats"$>@<0B8@>20BLHTML FormatHtml treeformats1I89"8? GenericType treeformats =0G>:Icon treeformats"0G0;L=>5=0G5=85 InitialValue treeformats4 0745;8B5;L-;5<5=B>2!?8A:0 ListSeparator treeformatsC<!B@>:8NumLines treeformats$>@<0BK2>40 OutputFormat treeformats@8AB02:0Prefix treeformats!>@B?5@54 SortForward treeformats><!>@B; SortKeyNum treeformats@>15;564C SpaceBetween treeformats:>=G0=85Suffix treeformats"TYPE treeformats"01;8F0Table treeformats$>@<0B03>;>2:0 TitleFormat treeformats&8@=K9 (@8DB &Bold Fonttreelocalcontrol&>?8@>20BL&Copytreelocalcontrol&#40;8BL #75; &Delete Nodetreelocalcontrol&B45;8BL ;>=K&Detach Clonestreelocalcontrol$&-:A?>@B8@>20BL... &Export...treelocalcontrol.&=5H=OO 8?5@AAK;:0...&External Link...treelocalcontrol& 07<5@ (@8DB0 &Font Sizetreelocalcontrol&428=CBL #75; &Indent Nodetreelocalcontrol &0:;>==K9 (@8DB &Italic Fonttreelocalcontrol$&5@5<5AB8BL 25@E&Move Uptreelocalcontrol&>2>5 :=> &New Windowtreelocalcontrol&AB028BL&Pastetreelocalcontrol&5G0BL... &Print...treelocalcontrol&>2B>@&Redotreelocalcontrol &1=>28BL !AK;:8&Regenerate Referencestreelocalcontrol&5@58<5=>20BL&Renametreelocalcontrol&!>E@0=8BL&Savetreelocalcontrol&&07=0G8BL "8? #7;0&Set Node Typetreelocalcontrol2&@>25@:0 @02>?8A0=8O...&Spell Check...treelocalcontrol&B<5=0&Undotreelocalcontrol&K428=CBL #75;&Unindent Nodetreelocalcontrol.>1028BL &>G5@=89 #75; Add &Childtreelocalcontrol<>1028BL &#@>25=L 0B53>@88...Add Category &Level...treelocalcontrold>1028BL =>2K9 4>G5@=89 C75; : 2K1@0==><C @>48B5;N Add new child to selected parenttreelocalcontrolt>1028BL 8;8 87<5=8BL 2=5H==NN 38?5@AAK;:C =0 web-AB@0=8FC!Add or modify an extrnal web linktreelocalcontrolh>1028BL 8;8 87<5=8BL 2=CB@5==NN 38?5@AAK;:C =0 C75;#Add or modify an internal node linktreelocalcontrolH52>7<>6=> @0AH8@8BL 157 >1I8E ?>;59#Cannot expand without common fieldstreelocalcontrol>;O 0B53>@88Category Fieldstreelocalcontrol0G8AB8BL $>&@<0B8@>20=85Clear For&mattingtreelocalcontrolrG8AB8BL =0AB@>9:8 D>@<0B0 B5:CI53> 8;8 2K1@0==>3> B5:AB0)Clear current or selected text formattingtreelocalcontrol@;>=8@>20BL A5 &>4>H54H85 #7;KClone All &Matched NodestreelocalcontrolD1J548=8BL ?>B><:>2 A;8O=85< ?>;59&Collapse descendants by merging fieldstreelocalcontrolT>=25@B8@>20BL 2A5 ?>4>H54H85 C7;K 2 :;>=K&Convert all matching nodes into clonestreelocalcontrolB>=25@B8@>20=> {0} 25B259 2 :;>=K"Converted {0} branches into clonestreelocalcontrol8>?8@>20BL "8?K 87 &$09;0...Copy Types from &File...treelocalcontrolR>?8@>20BL 25B2L 8;8 B5:AB 2 1CD5@ >1<5=0(Copy the branch or text to the clipboardtreelocalcontrold!:>?8@>20BL :>=D83C@0F8N 87 4@C3>3> D09;0 Treeline1Copy the configuration from another TreeLine filetreelocalcontrolK&@570BLCu&ttreelocalcontrolfK@570BL 25B2L 8;8 B5:AB 8 ?><5AB8BL 2 1CD5@ >1<5=0'Cut the branch or text to the clipboardtreelocalcontrol> #<>;G0=8NDefaulttreelocalcontrol,#40;8BL 2K1@0==K5 C7;KDelete the selected nodestreelocalcontrol`B45;8BL 2A5 :;>=8@>20==K5 C7;K 2 B5:CI8E 25B2OE+Detach all cloned nodes in current branchestreelocalcontroljH81:0  =52>7<>6=> C40;8BL @575@2=CN :>?8N D09;0 {0}'Error - could not delete backup file {}treelocalcontrolFH81:0  =5 <>3C ?@>G8B0BL D09; {0}Error - could not read file {0}treelocalcontrolBH81:0  =52>7<>6=> 70?8A0BL D09;Error - could not write to filetreelocalcontrol<H81:0  =5 <>3C 70?8A0BL 2 {}Error - could not write to {}treelocalcontrolR-:A?>@B8@>20BL D09; 2 @O4 4@C38E D>@<0B>2(Export the file in various other formatstreelocalcontrolV-:A?>@B 2 PDF A B5:CI8<8 =0AB@>9:0<8 ?5G0B8+Export to PDF with current printing optionstreelocalcontrol$09; A>E@0=5= File savedtreelocalcontrolH!25AB8 =0 48= #@>25=L &?> 0B53>@88Flatten &by Categorytreelocalcontrol&&25B (@8DB0...Font C&olor...treelocalcontrol@8=C48B5;L=>5 >1=>2;5=85 2A5E CA;>2=KE B8?>2 & ?>;59 <0B5<0B8G5A:8E ?>;593Force update of all conditional types & math fieldstreelocalcontrol.428=CBL 2K1@0==K5 C7;KIndent the selected nodestreelocalcontrolAB028BL &0BC Insert &Datetreelocalcontrol>!>740BL !5AB@8=A:89 #75; &>A;5Insert Sibling &Aftertreelocalcontrol>!>740BL !5AB@8=A:89 #75; &5@54Insert Sibling &BeforetreelocalcontrolV!>740BL C7;K :0B53>@89 =04 4>G5@=8<8 C7;0<8$Insert category nodes above childrentreelocalcontrol>AB028BL B5:CICN 40BC :0: B5:ABInsert current date as texttreelocalcontrol^!>740BL =>2K9 A5AB@8=A:89 C75; ?>A;5 2K1@0==>3>"Insert new sibling after selectiontreelocalcontrol\!>740BL =>2K9 A5AB@8=A:89 C75; ?5@54 2K1@0==K<#Insert new sibling before selectiontreelocalcontrol2&=CB@5=OO 8?5@AAK;:0...Internal &Link...treelocalcontrol>;LH>9Largetreelocalcontrol>;LH89Largertreelocalcontrol081>;LH89Largesttreelocalcontrol"5&@5<5AB8BL =87 M&ove DowntreelocalcontrolN5@5<5AB8BL 2 &0G0;> [2=CB@8 @>48B5;O] Move &FirsttreelocalcontrolL5@5<5AB8BL 2 &>=5F [2=CB@8 @>48B5;O] Move &Lasttreelocalcontrol>5@5<5AB8BL 2K1@0==K5 C7;K 2=87Move the selected nodes downtreelocalcontrolf5@5<5AB8BL 2K1@0==K5 C7;K =0 <5AB> ?5@2KE 4>G5@=8E0Move the selected nodes to be the first childrentreelocalcontroll5@5<5AB8BL 2K1@0==K5 C7;K =0 <5AB> ?>A;54=8E 4>G5@=8E/Move the selected nodes to be the last childrentreelocalcontrol@5@5<5AB8BL 2K1@0==K5 C7;K 225@EMove the selected nodes uptreelocalcontrol445=B8G=K5 C7;K =5 =0945=KNo identical nodes foundtreelocalcontrolBB:@KBL MB>B 65 D09; 2 =>2>< >:=5#Open a new window for the same filetreelocalcontrol(0AB@>9:0 &5G0B8...P&rint Setup...treelocalcontrol.&AB028BL @>AB>9 "5:ABPa&ste Plain Texttreelocalcontrol.AB028BL &>G5@=89 #75; Paste C&hildtreelocalcontrolJAB028BL &;>=8@>20==K9 >G5@=89 #75;Paste Cl&oned Childtreelocalcontrol\AB028BL &;>=8@>20==K9 !5AB@8=A:89 #75; 5@54Paste Clo&ned Sibling Beforetreelocalcontrol\AB028BL &;>=8@>20==K9 !5AB@8=A:89 #75; >A;5Paste Clone&d Sibling Aftertreelocalcontrol@AB028BL !5AB@8=A:89 #75; &>A;5Paste Sibling &Aftertreelocalcontrol@AB028BL !5AB@8=A:89 #75; &5@54Paste Sibling &BeforetreelocalcontrolZAB028BL :;>= 4>G5@=53> C7;0 87 1CD5@0 >1<5=0&Paste a child clone from the clipboardtreelocalcontrolNAB028BL 4>G5@=89 C75; 87 1CD5@0 >1<5=0%Paste a child node from the clipboardtreelocalcontrolTAB028BL A5AB@8=A:89 C75; ?>A;5 2K1@0==>3>Paste a sibling after selectiontreelocalcontrolRAB028BL A5AB@8=A:89 C75; ?5@54 2K1@0==K< Paste a sibling before selectiontreelocalcontrol`AB028BL :;>= A5AB@8=A:>3> C7;0 ?>A;5 2K1@0==>3>%Paste a sibling clone after selectiontreelocalcontrol^AB028BL :;>= A5AB@8=A:>3> C7;0 ?5@54 2K1@0==K<&Paste a sibling clone before selectiontreelocalcontrolPAB028BL C7;K 8;8 B5:AB 87 1CD5@0 >1<5=0&Paste nodes or text from the clipboardtreelocalcontrolbAB028BL =5D>@<0B8@>20==K9 B5:AB 87 1CD5@0 >1<5=0+Paste non-formatted text from the clipboardtreelocalcontrol 5G0BL 2 &PDF...Print &to PDF...treelocalcontrolF@5420@8B5;L=K9 @>&A<>B@ 5G0B8...Print Pre&view...treelocalcontrol 0A?5G0B0BL 284 45@520 =0 2KE>45 2 A>>B25BAB288 A B5:CI8<8 =0AB@>9:0<8*Print tree output based on current optionstreelocalcontrol&!2>9AB20...Prop&erties...treelocalcontrol>>2B>@8BL ?@54H5AB2CNICN >B<5=CRedo the previous undotreelocalcontrol`5@58<5=>20BL 703>;>2>: B5:CI53> M;5<5=B0 45@520#Rename the current tree entry titletreelocalcontrolD&><5=OBL 5AB0<8 #@>2=8 0B53>@88S&wap Category Levelstreelocalcontrol"!>E@0=8BL &0:... Save &As...treelocalcontrol!>E@0=8BL $09; Save Filetreelocalcontrol4!>E@0=8BL 87<5=5=8O 2 {0}?Save changes to {}?treelocalcontrol(!>E@0=8BL 87<5=5=8O? Save changes?treelocalcontrol,!>E@0=8BL B5:CI89 D09;Save the current filetreelocalcontrol>!>E@0=8BL D09; ?>4 =>2K< 8<5=5<Save the file with a new nametreelocalcontrol>K15@8B5 ?>;O 4;O =>2>3> C@>2=OSelect fields for new leveltreelocalcontrol0#AB0=>28BL  07<5@ (@8DB0 Set Font Sizetreelocalcontrol$07=0G8BL "8? #7;0 Set Node Typetreelocalcontroll07=0G8BL B0:85 ?0@0<5B@K, :0: :><?@5AA8O 8 H8D@>20=853Set file parameters like compression and encryptiontreelocalcontrol0AB@>8BL ?>;O, @07<5@ AB@0=8FK 8 CAB0=>28BL 4@C385 =0AB@>9:8 ?5G0B81Set margins, page size and other printing optionstreelocalcontrol^07=0G8BL @07<5@ B5:CI53> 8;8 2K1@0==>3> B5:AB0(Set size of the current or selected texttreelocalcontrolZ07=0G8BL F25B B5:CI53> 8;8 2K1@0==>3> B5:AB0-Set the color of the current or selected texttreelocalcontrolT!45;0BL B5:CI89 8;8 2K1@0==K9 H@8DB 68@=K<(Set the current or selected font to boldtreelocalcontrolZ!45;0BL B5:CI89 8;8 2K1@0==K9 H@8DB =0:;>==K<*Set the current or selected font to italictreelocalcontrol^!45;0BL B5:CI89 8;8 2K1@0==K9 B5:AB 70G5@:=CBK<0Set the current or selected font to strikethoughtreelocalcontrol`!45;0BL B5:CI89 8;8 2K1@0==K9 B5:AB ?>4G5@:=CBK<-Set the current or selected font to underlinetreelocalcontrolL07=0G8BL B8? C7;0 4;O 2K1@0==KE C7;>2$Set the node type for selected nodestreelocalcontrolh>:070BL ?@5420@8B5;L=K9 ?@>A<>B@ @57C;LB0B>2 ?5G0B8"Show a preview of printing resultstreelocalcontrol0;5=L:89SmalltreelocalcontrolL@>25@8BL ?@02>?8A0=85 B5:AB0 2 45@525 Spell check the tree's text datatreelocalcontrol$&0G5@:=CBK9 (@8DBSt&rikethrough FonttreelocalcontrolV><5=OBL C7;K 4>G5@=59 8 2=CG0B>9 :0B53>@89(Swap child and grandchild category nodestreelocalcontrolHTreeLine  B:@KBL $09; >=D83C@0F88"TreeLine - Open Configuration Filetreelocalcontrol0TreeLine  !>E@0=8BL 0:TreeLine - Save Astreelocalcontrol&>4&G5@:=CBK9 (@8DBU&nderline Fonttreelocalcontrol8B<5=8BL ?@54K4CI55 459AB285Undo the previous actiontreelocalcontrol0K428=CBL 2K1@0==K5 C7;KUnindent the selected nodestreelocalcontrol& TreeLine...&About TreeLine...treemaincontrol&A=>2K...&Basic Usage...treemaincontrol,&B<5=0 B:@KB8O $09;0&Cancel File Opentreemaincontrol$&#A;>2=K9 >8A:...&Conditional Find...treemaincontrol2&0AB@>8BL "8?K 0==KE...&Configure Data Types...treemaincontrol:#40;8BL D09; & 575@2=>9 >?88&Delete Backuptreemaincontrol &>8A: "5:AB0... &Find Text...treemaincontrol.&>;=0O >:C<5=B0F8O...&Full Documentation...treemaincontrol&&1I85 0@0<5B@K...&General Options...treemaincontrol"&<?>@B8@>20BL... &Import...treemaincontrol&>2K9...&New...treemaincontrol&B:@KBL...&Open...treemaincontrol &KE>4&QuittreemaincontrolL&>AAB0=>28BL 87 @575@2=>9 :>?88 D09;0&Restore Backuptreemaincontrol&K1@0BL 2A5 &Select Alltreemaincontrol&K1@0BL @8<5@&Select Sampletreemaincontrol&K1@0BL (01;>=&Select Templatetreemaincontrol(&"5:AB>2K9 $8;LB@...&Text Filter...treemaincontrol<55BAO @575@2=0O :>?8O D09;0 {}. >7<>6=> ?@54K4CI0O A5AA8O 1K;0 020@89=> 7025@H5=02=K9 $8;LB@...C&onditional Filter...treemaincontrolB&0AB@>8BL 0=5;8 8=AB@C<5=B>2...C&ustomize Toolbars...treemaincontrol#A;>2=K9 $8;LB@Conditional Filtertreemaincontrol#A;>2=K9 >8A:Conditional Findtreemaincontrol&0AB@>8BL &&25B0...Custo&mize Colors...treemaincontrol(0AB@>8BL (&@8DBK...Customize Fo&nts...treemaincontrol40AB@>8BL F25B0 8 B5<K GUICustomize GUI colors and themestreemaincontrolT0AB@>8BL H@8DBK 4;O @07=KE D>@< ?@>A<>B@0 Customize fonts in various viewstreemaincontrol80AB@>8BL :><0=4K :;0280BC@KCustomize keyboard commandstreemaincontrolN0AB@>8BL :=>?:8 =0 ?0=5;8 8=AB@C<5=B>2Customize toolbar buttonstreemaincontrolB040BL ?0@0<5B@K A>@B8@>2:8 C7;>2Define node sort operationstreemaincontrolR>:070BL >A=>2=K5 8A?>;L7C5<K5 8=AB@C:F88 Display basic usage instructionstreemaincontrolH>:070BL A2545=8O > 25@A88 ?@>3@0<<K'Display version info about this programtreemaincontrolpH81:0  D09; A?@02:8 ?> >A=>20< 8A?>;L7>20=8O =5 =0945=!Error - basic help file not foundtreemaincontrolLH81:0  =52>7<>6=> ?@>G8B0BL D09; {0}Error - could not read file {0}treemaincontrolbH81:0  =52>7<>6=> C40;8BL @575@2=CN :>?8N D09;0'Error - could not remove backup file {}treemaincontrolVH81:0  =52>7<>6=> ?5@58<5=>20BL {0} 2 {1}'Error - could not rename "{0}" to "{1}"treemaincontrol`H81:0  =5 <>3C 70?8A0BL D09; :>=D83C@0F88 2 {})Error - could not write config file to {}treemaincontrolHH81:0  D09; 4>:C<5=B0F88 =5 =0945=$Error - documentation file not foundtreemaincontrolPH81:0  =525@=K9 D09; D09; Treeline {0}!Error - invalid TreeLine file {0}treemaincontrol&K9B8 87 ?@8;>65=8OExit the applicationtreemaincontrold$8;LB@>20BL C7;K, ?>:0702 B>;L:> A>2?045=8O B5:AB0&Filter nodes to only show text matchestreemaincontrol$>8A: 8 &0<5=0...Find and &Replace...treemaincontrolN09B8 B5:AB 2 703>;>2:0E C7;>2 & 40==KEFind text in node titles & datatreemaincontrol1I85 0@0<5B@KGeneral Optionstreemaincontrol"5@A88 181;8>B5::Library versions:treemaincontrolT7<5=8BL B8?K 40==KE, ?>;O & AB@>:8 2K2>40(Modify data types, fields & output linestreemaincontrol>2K9 $09;New FiletreemaincontrolB:@KBL $09; Open Filetreemaincontrol$B:@KBL &@8<5@...Open Sa&mple...treemaincontrolB:@KBL @8<5@ Open Sampletreemaincontrol(B:@KBL $09; @8<5@0Open Sample FiletreemaincontroljB:@KBL D09; Treeline, A>45@60I89 ?>;=CN 4>:C<5=B0F8N,Open a TreeLine file with full documentationtreemaincontrol(B:@KBL D09; A 48A:0Open a file from disktreemaincontrol0B:@KBL =5-Treeline D09;Open a non-TreeLine filetreemaincontrol(B:@KBL D09; ?@8<5@0Open a sample filetreemaincontrolB0<5=8BL B5:AB>2K5 AB@>:8 2 C7;0E!Replace text strings in node datatreemaincontrol<K1@0BL 25AL B5:AB 2 @540:B>@5Select all text in an editortreemaincontrol:&07=0G8BL >@OG85 ;028H8...Set &Keyboard Shortcuts...treemaincontrol`07=0G8BL CAB0=>2:8 ?>;L7>20B5;O 4;O 2A5E D09;>2"Set user preferences for all filestreemaincontrolR>:070BL !&:>=D83C@8@>20==CN !B@C:BC@C... Show C&onfiguration Structure...treemaincontrol>:070BL 4>ABC?=>5 B>;L:> 4;O GB5=8O ?@54AB02;5=85 AB@C:BC@K B8?>2.Show read-only visualization of type structuretreemaincontrol(&!>@B8@>20BL #7;K...Sor&t Nodes...treemaincontrol$!>740BL =>2K9 D09;Start a new filetreemaincontrol.TreeLine  B:@KBL $09;TreeLine - Open Filetreemaincontrol:A=>2K 8A?>;L7>20=8O TreeLineTreeLine Basic Usagetreemaincontrol&5@A8O TreeLine {0}TreeLine version {0}treemaincontrol,1=>28BL &C<5@0F8N...Update &Numbering...treemaincontrol.1=>28BL ?>;O =C<5@0F88Update node numbering fieldstreemaincontrollA?>;L7>20BL CA;>28O 2K1>@0 ?>;59 4;O D8;LB@0F88 C7;>2$Use field conditions to filter nodestreemaincontrollA?>;L7>20BL CA;>28O 2K1>@0 ?>;59 4;O D8;LB@0F88 C7;>2"Use field conditions to find nodestreemaincontrolX=8<0=85: 52>7<>6=> A>740BL ;>:0;L=K9 A>:5B'Warning: Could not create local sockettreemaincontrol0>BACBAB2CNI0O 48@5:B>@8Omissing directorytreemaincontrol02B>@ {0}written by {0}treemaincontrol >2K9Newtreenode;02=K9Main treestructureL#A;>2=0O D8;LB@0F8O, C7;>2 =0945=> {0}&Conditional filtering, found {0} nodestreeviewRBD8;LB@>20=> ?> "{0}", C7;>2 =0945=> {0}#Filtering by "{0}", found {1} nodestreeview!;54CNI89: {0} Next: {0}treeview6!;54CNI89: {0} (=5 =0945=>)Next: {0} (not found)treeview 09B8: Search for:treeview09B8: {0}Search for: {0}treeview.09B8: {0} (=5 =0945=>)Search for: {0} (not found)treeview&0:@KBL :=> &Close Window treewindow&&!25@=CBL AN 5B2L&Collapse Full Branch treewindow&0==K5&Data treewindow&@02:0&Edit treewindow*& 0725@=CBL AN 5B2L&Expand Full Branch treewindow &$09;&File treewindow&!?@02:0&Help treewindow &!;54CNI89 K1>@&Next Selection treewindow &#75;&Node treewindow"&@54K4CI89 K1>@&Previous Selection treewindow>&>:070BL 0=5;L >G5@=53> #7;0&Show Child Pane treewindow&=AB@C<5=BK&Tools treewindow&84&View treewindow &:=>&Window treewindow 0:@KBL MB> >:=>Close this window treewindowT!25@=CBL 2A5 4>G5@=85 C7;K 2K1@0==KE C7;>2+Collapse all children of the selected nodes treewindow 540:B>@ 0==KE Data Edit treewindowK2>4 0==KE Data Output treewindowT 0A:@KBL 2A5 4>G5@=85 C7;K 2K1@0==KE C7;>2)Expand all children of the selected nodes treewindow&$>@<0BFo&rmat treewindowJ5@59B8 : A;54CNI5<C 2K1>@C 2 8AB>@88(Go to the next tree selection in history treewindow2>H03>2> A:0BL !;54CNI89Next Incremental Search treewindow4>H03>2> A:0BL @54K4CI89Previous Incremental Search treewindowN5@=CBLAO : ?@54K4CI5<C 2K1>@C 2 45@525%Return to the previous tree selection treewindow>>:070BL &02830F8>==CN F5?>G:CShow &Breadcrumb View treewindow6>:070BL !?8A>: &03>;>2:>2Show &Title List treewindow2>:070BL & 540:B>@ 0==KEShow Data &Editor treewindow,>:070BL &K2>4 0==KEShow Data &Output treewindow0>:070BL K2>4 &>B><:>2Show Output &Descendants treewindowN>:070BL @540:B>@ 40==KE 2 D>@<5 A?@020Show data editor in right view treewindowH>:070BL 2K2>4 40==KE 2 D>@<5 A?@020Show data output in right view treewindowR>:070BL A?8A>: 703>;>2:>2 2 D>@<5 A?@020Show title list in right view treewindow,0G0BL >H03>2K9 >8A:Start Incremental Search treewindow"!?8A>: 03>;>2:>2 Title List treewindowf5@5:;NG8BL =0 ?>:07 =02830F8>==>9 F5?>G:8 : ?@54:C'Toggle showing breadcrumb ancestor view treewindowL5@5:;NG8BL ?>:07 ?>B><:>2 A >BABC?0<8/Toggle showing output view indented descendants treewindowd5@5:;NG8BL =0 ?>:07 4>G5@=8E C7;>2 2 D>@<5 A?@020%Toggle showing right-hand child views treewindow ) , TreeLine-3.2.1/translations/treeline_zh.qm000066400000000000000000002173621506556630100206360ustar00rootroot00000000000000Yg#hDm'ex,I[&HXrulHKv%wDx0z^y^70Ke78OH5H5fU~VE9c SEXh5X,Se"D0K5[R7~8&Q* %*^*y***%K*TI*6%*0{*5_ +5t+U+++m++8A+:+įR+/55S4 ;0|c nE_%v{-+6nd6n[6n;Y =!>6OGSR5-_ c gx?|`-ۇR*W%GZ >wi|eJ~ |g_~ҮN%| <~C JuwL 4% %Lom*tBU\~~#_.E1SÅ9ځ9@b D"NBN$I!R fXMP[ó*aLJa2f@ggli 5lwploFs,z6}'~ov.t?dn@B@{bFJ\8R``}Cf4gNehT?yh!rGIx*3z}+G`NcB%G%53cCIN%JcT(NK.Fakz+%"DuϑMĮeT )ל5jשD"Kؙ<:Kg?kH]Sh!Pmym/Ns t d#[IѤcy1_~nhUb#C9#Cb&$͕*,+. //_7/y0?mIn3\L RSS"kZzZ]_Pb#pCe,ffȊ7gGlr^PhOnZ:ITi$ ~|&ϥ&K@.o.}R@i˃~"Ψa4`7ie 7Qx_qE>TT&4ҀY7 .|&k 3&t\(m36)*/}O0nd7OF]8OFCd_P[R99VSU۾U]15hEkkNn?ninUp\{}\<nDo`?Nߠue/1/ [2Ǩ_˛tOe^"ufkE3vj^8fOZųA - '*Sey,0 1cD{1cDF9H`@EamFytLC\W$:Yh[%ZH]!bbn#,wƾyYB{0>6P |9[cc_pcyMHnjTz_ ©PMq*)VH9Po&t^ =%%ns%%`xA)̇$,q%oJU>EԤ?VK޹߂3ߗevu+a ^Ym ҷb r  \~ \~ ;) q#! - ! 4Ed 5 :rN F LV MgZ f+>G kY dT 81  " ωiK \H j bbH { b*5 ld7 W ߡX  =  , p ʵ tKa n# O eI  L) f cY V Ӆ .j TQ T]e  W(X ,_$$i /& 4 5ru 7* =! ITE Ty U Wܾ)2 _҉ ae c5< cP e uo~ u5 w5mw ăD 52 1y 3\~ : I I I I0I Ik I I I CS 8r 9G /  ,0 6" 5  ' ^& I9 - & t ˈ ĽNR ;: Gc : :lZ 5 l  ; 5 e3H {O 9 s|Q .n.  to~ X K2v )M -8Z .2ּ /. 2  5# 93 @(e AN Ks3 KI L.\ L9W W X [tJ pI3[y rWh x( x( {u@ :3 jX sm?  HQ  ; O Z/ i" -? D7 (c ]Pr 8  D Ip B ~p t0 ٷm ߺc KG ~ \E K ^Ѱ y~ɒ + vh w A E 2B +0 P % #, Q lJ G # '{ (E3 * s 2l 7"!V 8ǑR ;y* =` @|5p @ V dMK g#% n/ pki tf tc tU v" {Bqd =7j e_ hl MC T6   CK 4p ev m)1 ү v bnF D Ux Y\ \ -w 3X  'i . 0u9 0 3T 7y* C G9.h H Kz9a Ki M S NK# ]`^JR _ T dT i'9 i$^ i$l m. z  27  ݃y |1" =$ cE DD ˜S! D^ X s9 ~t > st :I,Y dcx"<sIs=(tz$(Y-z/+!0/E0>EN9 = EjH;\L`L^OL[JL^V(Y Zrhj8i?Oklfcp#4#qtt/C[Dbx^Ae-STtSybUte:Kk\D-`E1ԕXՁYe#9fh\ tppVCu.~`n;> jKc R(x68 qV<s@-HNI0|MU Z8n[Ke3em3:|iFW.rxs$§ww |*}$7!?y A ӝԲ) Q']t2IMmU4nc#HMY3՜u"$&$| ɟ)N~#]-jo+hoDrds7Q3]%6fWCi Sm(&C)&Cancelcolorset xn(&O)&OKcolorsetr_iN; Color ThemecolorsetmReR(&A) &Add New Rule conditional Sm(&C)&Cancel conditional Qs(&C)&Close conditional R d(&D)&Delete conditional~g_n(&E) &End Filter conditional n(&F)&Filter conditional }Qe(&L)&Load conditional xn(&O)&OK conditionalR dR(&R) &Remove Rule conditional O[X(&S)&Save conditionalPGFalse conditionalgb~N NN*(&N) Find &Next conditionalgb~N NN*(&P)Find &Previous conditionalT [W:Name: conditionallg b~R0gaNS9M!No conditional matches were found conditionalp|{W Node Type conditional R{0}Rule {0} conditionalO[XR Saved Rules conditionalwTrue conditional [b@g |{W] [All Types] conditionalNand conditionalST+contains conditional N...~\> ends with conditionalbor conditional N..._Y starts with conditional ^u((&A)&Apply configdialog Sm(&C)&Cancel configdialogepcn|{W(&D) &Data Type configdialogR d|{W(&D) &Delete Type configdialogNSge|{WMu(&D)&Derive from original configdialogez _(&E) &Equation configdialog[WkMn(&F) &Field Config configdialog[Wk|{W(&F) &Field Type configdialogϚ~(&H)&Hide Advanced configdialog N y(&M) &Move Down configdialoge[Wk(&N)... &New Field... configdialoge|{W(&N)... &New Type... configdialog xn(&O)&OK configdialog RM(&P)&Prefix configdialog n(&R)&Reset configdialog~g|{W(&R) &Result Type configdialog bb@g (&S) &Select All configdialogf>y:~(&S)&Show Advanced configdialogc^hQ(&S)&Sort Criteria configdialoghh<_(&T) &Title Format configdialogW(pNKmRzzL(&b)Add &blank lines between nodes configdialogmR[Wk Add Field configdialogmR|{WAdd Type configdialogmRbR depcn|{WAdd or Remove Data Types configdialogmReg,yv{&S(&s)Add text bullet&s configdialogQA&HTMLYh<_eg,Allow &HTML rich text in format configdialog {g/{{&Arithmetic Operators configdialogR|{WAutomatic Types configdialogSu([WkRh(&F)Available &Field List configdialogSu([Wk(&F)Available &Fields configdialog^\~gBoolean Result configdialogelR dpOu(vepcn|{W+Cannot delete data type being used by nodes configdialoge9SVh(&I) Change &Icon configdialog[Pep Child Count configdialog[P_u(Child Reference configdialog [P|{WPR6Child Type Limits configdialognd b(&S) Clear &Select configdialogb|{W(&p)... Co&py Type... configdialog ~T&&[PRhQR{&(&S)+Combination && Child List Output &Separator configdialog kԏ{{&Comparison Operators configdialog Mnepcn|{WConfigure Data Types configdialogY R6|{W Copy Type configdialogepCount configdialogR^gaN|{W(&n)Create Co&nditional Types configdialogeg~g Date Result configdialogepv:wP<(&V)Default &Value for New Nodes configdialog؋[Pp|{W(&T)Default Child &Type configdialog [NIez _Define Equation configdialog[NIep[f[Wkez Define Math Field Equation configdialogR d[Wk(&t) Dele&te Field configdialogNΐu(|{WMu(&G)Derived from &Generic Type configdialogcϏ Description configdialogeT Direction configdialog Vh^ Editor Height configdialogQeev[WkT y:Enter new field name: configdialogQee|{WvT [W:Enter new type name: configdialogez _{}Equation error: {} configdialog  - ep[fW:ez N-v_s_u(2Error - circular reference in math field equations configdialogO0&HTMLhEvaluate &HTML tags configdialogYe[W Extra Text configdialog [Wk(&i)F&ield configdialog[WkRh(&i) F&ield List configdialog[WkField configdialog[WkRh(&L) Field &List configdialog[Wk_u(Field References configdialog eNO`oS€File Info Reference configdialogleT(&D)Flip &Direction configdialogh<_^.R(&H) Format &Help configdialogVhIcon configdialog ep[fez _ Math Equation configdialogOe9[WkRh(&F)Modify &Field List configdialogOe9gaN|{W(&n)Modify Co&nditional Types configdialog N y(&U)Move &Up configdialog N y(&w) Move Do&wn configdialog N y(&p)Move U&p configdialogT [WName configdialogeNone configdialogeg,Lep(&b)Num&ber of text lines configdialogep[W~g Number Result configdialog [PpepNumber of Children configdialog{|{W(&p)O&perator Type configdialog Q(&u)O&utput configdialog{Rh(&a)Oper&ator List configdialog{ Operations configdialog QvN[WkS€Other Field References configdialogQh<_(&p)Out&put Format configdialogQh<_(&t)Outpu&t Format configdialog QHTML Output HTML configdialogQ yOutput Options configdialogr6_u(Parent Reference configdialogS€|{W(&n)Refere&nce Type configdialog_u(~R+(&L)Reference &Level configdialog_u(|{W(&T)Reference &Type configdialogS€~R+(&v)Reference Le&vel configdialogT}T [Wk(&m)...Rena&me Field... configdialogT}T |{W(&m)...Rena&me Type... configdialog T}T [Wk Rename Field configdialog T}T |{W Rename Type configdialogN{}T}T N::Rename from {} to: configdialogh9_u(Root Reference configdialogN (&N) Select &None configdialog_u(Self Reference configdialognepcn|{WVhSet Data Type Icon configdialogg gaNW0n|{WSet Types Conditionally configdialogc^.(&K)... Sort &Keys... configdialogc^.Sort Key configdialog c^Qs.[WkSort Key Fields configdialog T(&x)Suffi&x configdialog|{WRh(&y) T&ype List configdialog eg,{{&Text Operators configdialogeg,~g Text Result configdialogN QAOu(NN [W{&{},The following characters are not allowed: {} configdialog T yN N:zzThe name cannot be empty configdialogT yN ST+zzh<The name cannot contain spaces configdialogT yN N xml _Y4 The name cannot start with "xml" configdialogT y_Ř{N[Wk_Y4!The name must start with a letter configdialogT y]Ou(The name was already used configdialoge~g Time Result configdialog|{WMn(&e) Typ&e Config configdialog|{WType configdialogN:[WkepcnOu(hh<(&d)Use a table for field &data configdialog[b@g Su(|{W][All Types Available] configdialog[e][None] configdialog~[P<absolute value configdialogRadd configdialogSOY_& arc cosine configdialogkc_&larc sine configdialogSkcR arc tangent configdialog^sWGaverage configdialogN10N:^v[epbase-10 logarithm configdialogceg,concatenate text configdialog\eg,lcbN:\Qconvert text to lower case configdialog\eg,lcbN:Y'Qconvert text to upper case configdialogOY_&cosine of radians configdialog ^epR0_'^degrees to radians configdialogddivide configdialog{INequal to configdialog6NX factorial configdialogmnpfloating point configdialog TN Setd floor divide configdialogkcTforward configdialogkcTfwd configdialogY'N greater than configdialogY'N{INgreater than or equal to configdialog*fvetep(higher integer)higher integer configdialog,W({,NN*SepN- \{,NN*SepfcbN:{,N N*Sep(in 1st arg, replace 2nd arg with 3rd arg configdialog Ou({,NN*SepO\N:R{&ceg,$join text using 1st arg as separator configdialog\N less than configdialog\N{INless than or equal to configdialog;N logical and configdialog;b logical or configdialog(ONvetep(lower integer) lower integer configdialoggY'maximum configdialogg\minimum configdialog|epmodulus configdialogNXmultiply configdialog q6[ep^8epnatural log constant configdialogq6[epnatural logarithm configdialogN {I not equal to configdialog^8ep pi constant configdialogNXepower configdialog_'^R0^radians to degrees configdialogTrev configdialogTreverse configdialogVۂ NQeround to num digits configdialogkc_&sine of radians configdialog^seh9 square root configdialogQsubtract configdialogyv`;T sum of items configdialog,R~(tangent of radians)tangent of radians configdialog(Yg{,NN*eg,SepST+{,NN*Sep RN:w%true if 1st text arg contains 2nd arg configdialog*Yg{,NN*eg,SepN{,NN*Sep~\> RN:w&true if 1st text arg ends with 2nd arg configdialog*Yg{,NN*eg,SepN{,NN*Sep_Y4 RN:w(true if 1st text arg starts with 2nd arg configdialogwP<, gaN, PGP<"true value, condition, false value configdialog0b*evetep(truncated integer)truncated integer configdialogmOeN(&B)&Browse for File dataeditors Sm(&C)&Cancel dataeditorslR0vh(&G) &Go to Target dataeditors xn(&O)&OK dataeditorsbS_c(&O) &Open Link dataeditorsbS_VrG(&O) &Open Picture dataeditors(W(hN-pQcvh)(Click link target in tree) dataeditors~[Absolute dataeditorsW0W@Address dataeditorsndc(&L) Clear &Link dataeditorsf>y:T y Display Name dataeditorsYc External Link dataeditors eN_|{WFile Path Type dataeditorsQc Internal Link dataeditorsbS_eNY9(&F) Open &Folder dataeditorsVrGc Picture Link dataeditorsv[Relative dataeditorsehHScheme dataeditorsnN:_SRMe(&N) Set to &Now dataeditors_SRMeg(&D) Today's &Date dataeditors"TreeLine - YceNTreeLine - External Link File dataeditorsTreeLine - VrGeNTreeLine - Picture File dataeditorsclink dataeditors R(&C)&Columnsexports.SR(CSV)TNhh<(~R+S)(&C);&Comma delimited (CSV) table of descendants (level numbers)exportsethh(&E) &Entire treeexports &HTML&HTMLexports&HTMLh<_vNf{~&HTML format bookmarksexportsSbh9p(&I)&Include root nodesexports &ODFY'~ &ODF Outlineexports.rHg,TreeLine (2.0.x)(&O)&Old TreeLine (2.0.x)exportsSg bS_pv[Pp(&O)&Only open node childrenexportsSUN*HTMLub(&S)&Single HTML pageexportsh{~he[W(&T)&Tabbed title textexports eg,(&T)&TextexportsTreeLine[Ph(&T)&TreeLine Subtreeexportsg*h<_Svb@g eg,Q(&U)&Unformatted output of all textexports&XBELh<_vNf{~&XBEL format bookmarksexports&XML (u()&XML (generic)exports Nf{~(&m) Book&marksexportsNf{~ Bookmarksexports b[Qh<_[P|{WChoose export format subtypeexports b[Qh<_|{WChoose export format typeexports b[Q yChoose export optionsexports(SR(CSV)[Phh<(SU~)(&d)7Comma &delimited (CSV) table of children (single level)exportsD - elՔcR0g*O[XvTreeLineeN0 O[XeN^v͋0FError - cannot link to unsaved TreeLine file. Save the file and retry.exports: - g*b~R0[Qj!geN0 hgTreeLine[0JError - export template files not found. Check your TreeLine installation.exportseN[Q File ExportexportsSbbSSphTu(&p)Include &print header && footerexports:[ehV cR0TreeLineeN(u(NWebg RVh)8Live tree view, linked to TreeLine file (for web server)exports [ehV SUN*eN(]LQeepcn)+Live tree view, single file (embedded data)exportsYN*HTMLTepcnh(&d)Multiple HTML &data tablesexports$^&[*zh!Digit or Space (external)  fieldformatpR{& \.Dot Separator \. fieldformat eg,~\> $ End of Text $ fieldformatryk[W{&lNI \Escape a Special Character \ fieldformatO[P 1/2/3/4Example 1/2/3/4 fieldformatcep (Y'Q) EExponent (capital) E fieldformatcep(\Q) eExponent (small) e fieldformatYc ExternalLink fieldformat6\e(0-23, 1 or 2 digits) %-HHour (0-23, 1 or 2 digits) %-H fieldformat,\e(00-23, 2 digits) %HHour (00-23, 2 digits) %H fieldformat.\e (01-12, 2 digits) %IHour (01-12, 2 digits) %I fieldformat8\e (1-12, 1 or 2 digits) %-IHour (1-12, 1 or 2 digits) %-I fieldformat Htmleg,HtmlText fieldformatQc InternalLink fieldformat ~R{& /Level Separator / fieldformat\Q[Wk [a-z]Lower Case Letters [a-z] fieldformatep[fMath fieldformat ky (6 digits) %fMicroseconds (6 digits) %f fieldformat*R (1 or 2 digits) %-MMinute (1 or 2 digits) %-M fieldformatR (2 digits) %MMinute (2 digits) %M fieldformat*g (1 or 2 digits) %-mMonth (1 or 2 digits) %-m fieldformatg (2 digits) %mMonth (2 digits) %m fieldformat g)Q %bMonth Abbreviation %b fieldformat gT [W %B Month Name %B fieldformat^ep[W [^0-9]Not a Number [^0-9] fieldformatsW(Now fieldformatep[WNumber fieldformatep 1Number 1 fieldformatS Numbering fieldformatSULeg, OneLineText fieldformat S ep[W #Optional Digit # fieldformat S h_ -Optional Sign - fieldformatb |Or | fieldformat,Y'~O[P I../A../1../a)/i)!Outline Example I../A../1../a)/i) fieldformatVrGPicture fieldformat kcRh_RegularExpression fieldformat _ŗep[W 0Required Digit 0 fieldformat_ŗvh_ +Required Sign + fieldformat*y (1 or 2 digits) %-SSecond (1 or 2 digits) %-S fieldformaty (2 digits) %SSecond (2 digits) %S fieldformatk=O[P 1.1.1.1Section Example 1.1.1.1 fieldformatk=R{& .Section Separator . fieldformat R{& / Separator / fieldformatep[W [0-9]Set of Numbers [0-9] fieldformat \Q[Wk aSmall Letter a fieldformat\QWlep[W iSmall Roman Numeral i fieldformat$zzh"Space Separator (internal)  fieldformateg, SpacedText fieldformatT/FT/F fieldformateg,Text fieldformateTime fieldformatY'Q[Wk [A-Z]Upper Case Letters [A-Z] fieldformat$fgep[W (0 to 53) %-UWeek Number (0 to 53) %-U fieldformatfg)Q %aWeekday Abbreviation %a fieldformatfgT [W %AWeekday Name %A fieldformatY/NY/N fieldformat^t (2 digits) %yYear (2 digits) %y fieldformat^t (4 digits) %YYear (4 digits) %Y fieldformattrue/false true/false fieldformat yes/noyes/no fieldformatPGfalse genbooleanT&no genbooleanwtrue genbooleanf/yes genbooleanb@g eN All Files globalrefb@g TreeLineeNAll TreeLine Files globalrefCSV(SR)eNCSV (Comma Delimited) Files globalref HTMLeN HTML Files globalrefODFeg,eNODF Text Files globalrefTreeLineeNOld TreeLine Files globalref PDFeN PDF Files globalrefeg,eN Text Files globalrefTreeLineeNTreeLine Files globalrefTreeLineeN - S)TreeLine Files - Compressed globalrefTreeLineeN - R[TreeLine Files - Encrypted globalrefTreepadeN Treepad Files globalref XMLeN XML Files globalrefgb~ Find: helpview V(&B)&Backhelpview RM(&F)&Forwardhelpview N;u(&H)&Homehelpviewgb~TNN*(&N) Find &Nexthelpviewgb~RMNN*(&P)Find &Previoushelpview lb~R0eg,N2Text string not foundhelpview]QwToolshelpview>"{0}"N f/g eHvTreeLineeN0 Ou([QenVh:"{0}" is not a valid TreeLine file. Use an import filter?imports,u(XML(^TreeLineeN)(&G) &Generic XML (non-TreeLine file)imports$&HTMLNf{~(Mozillah<_) &HTML bookmarks (Mozilla Format)imports&Tab)eg, kψLNN*p%&Tab indented text, one node per lineimports&XMLNf{~(XBELh<_)&XML bookmarks (XBEL format)importsNf{~BOOKMARKimportsL{0}N vCSVh<_Bad CSV format on Line {0}importsNf{~ Bookmarksimports b[Qee_Choose Import Methodimports<^&g ~R+R && hLvSR(CSV)eg,hh<(&m)ACo&mma delimited (CSV) text table with level column && header rowimports.^&g hLvSR(CSV)eg,hh<(&w)1Comma delimited (CSV) text table &with header rowimports - elՋSeN{0}Error - could not read file {0}imports  - {0}N-vh<_N kcxnError - improper format in {0}importsv_UFOLDERimports[QeeN Import Fileimports eeHveN Invalid Fileimports{,{0}LN v~R+SeeH Invalid level number on line {0}imports ~R+~geeHInvalid level structureimportscLinkimports.rHg,Tree&LineeN(1.xb2.x)Old Tree&Line File (1.x or 2.x)imports,Open &Document (ODF)Y'~Open &Document (ODF) outlineimportsQvNOtherimports"~eg,Nk=(zzv}LR)(&p)-Plain text ¶graphs (blank line delimited)imports(~eg, kψLNN*p(VޏfR)(&n)-Plain text, one &node per line (CR delimited)importsR{& SEPARATORimportshh<TABLEimports&^&hTLvTabReg,hh<(&r))Tab delimited text table with header &rowimportseg,TextimportsL{0}N vgavY*YToo many entries on Line {0}importsTreeLine - [QeeNTreeLine - Import Fileimports*TreepadeN(NŖPeg,p)(&f)Treepad &file (text nodes only)imports_Ř{W(QepN-~T[P_u(/Child references must be combined in a functionmatheval^lv"{}"[W{&Illegal "{}" charactersmatheval[XW(^lQep: {0}Illegal function present: {0}matheval^l[a|{Wb{{&: {0}$Illegal object type or operator: {0}matheval{I_N-v^lՋlIllegal syntax in equationmatheval ^u((&A)&Apply miscdialogs Sm(&C)&Cancel miscdialogs Qs(&C)&Close miscdialogs~g_n(&E) &End Filter miscdialogsethh(&E) &Entire tree miscdialogs n(&F)&Filter miscdialogsgb~N NN*(&F) &Find Next miscdialogs kcT(&F)&Forward miscdialogs_ue^v(&I)&Ignore and skip miscdialogsQs.(&K) &Key words miscdialogsp|{W(&N) &Node Type miscdialogs xn(&O)&OK miscdialogs[NIvQs.[Wk(&P)&Predefined Key Fields miscdialogskcRh_(&R)&Regular expression miscdialogs fcb(&R)&Replace miscdialogs T/N NN*T ~pvS(&R)"&Restart numbers for next siblings miscdialogs`bY ؋(&R)&Restore Defaults miscdialogs ST(&R)&Reverse miscdialogsd}"e[W(&S) &Search Text miscdialogs b邂pv[Pp(&S)&Selection's children miscdialogsSg h(&T) &Titles only miscdialogs]Qwh(&T) &Toolbars miscdialogs\zzv}[WkN:(&T)&Treat blank fields as zeros miscdialogsOu(^u(؋[WOS(&U)&Use app default font miscdialogsOu(eNS)(&U)&Use file compression miscdialogsOu(|~ߞ؋[WOS(&U)&Use system default font miscdialogs - R{& -  --Separator-- miscdialogsSuNN%͕0 TreeLineSYNN z3[r`. ^W(SNN*eNT N O[XNOUeNfe9^veT/RTreeLine. N bf>y:vO`oSNY R6^vu5[PNSѐR0doug101@bellz.org [`Qv.A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances.  miscdialogsSu(T}N(&v)A&vailable Commands miscdialogsNaS9M(&m) Any &match miscdialogs ^u(؋[WOSApp Default Font miscdialogsnd.(&K) Clear &Key miscdialogs [NI[WOSCustomize Fonts miscdialogs [NI]QwhCustomize Toolbars miscdialogsepcnData miscdialogsepcnSU Data Menu miscdialogs؋ - SULe[WDefault - Single Line Text miscdialogsEdit miscdialogsSU Edit Menu miscdialogsVhV[WOSEditor View Font miscdialogs R[eN[xEncrypted File Password miscdialogs - eeHvkcRh_"Error - invalid regular expression miscdialogs - fcbY1%Error - replacement failed miscdialogs[etvw(&u) F&ull phrase miscdialogs[WkFields miscdialogseNFile miscdialogseNSU File Menu miscdialogseN\^`'File Properties miscdialogseN[XP File Storage miscdialogsnFilter miscdialogsgb~Find miscdialogsgb~N NN*(&N) Find &Next miscdialogsgb~N NN*(&P)Find &Previous miscdialogs gb~TfcbFind and Replace miscdialogsh<_Format miscdialogsh<_SU Format Menu miscdialogs[etepcn(&d) Full &data miscdialogs[etv(&w) Full &words miscdialogsYtlg S[Wkvp'Handling Nodes without Numbering Fields miscdialogs^.RHelp miscdialogs^.RSU Help Menu miscdialogsYOUd}" How to Search miscdialogs Sbv~pInclude top-level nodes miscdialogs[etvQs.(&w)Key full &words miscdialogs.{0}]Ou(Key {0} is already used miscdialogs .v_cw.Keyboard Shortcuts miscdialogsNxb [WQx(S )&Language code or dictionary (optional) miscdialogsY'Vh Large Icons miscdialogsep[f[Wk Math Fields miscdialogs N y(&D) Move &Down miscdialogs N y(&U)Move &Up miscdialogsp[Wk(&o) N&ode Fields miscdialogseSUNo menu miscdialogsW(epcn|{WN-b~N R0S[Wk,No numbering fields were found in data types miscdialogspNode miscdialogsph(&T) Node &Titles miscdialogspSU Node Menu miscdialogs QV[WOSOutput View Font miscdialogskcRh_(&g)Re&gular expression miscdialogseQe[x:Re-Type Password: miscdialogseQev[xN S9MRe-typed password did not match miscdialogsW(kdOgOO[x%Remember password during this session miscdialogsfcbQh(&A) Replace &All miscdialogsfcbN{0}N*S9MyReplaced {0} matches miscdialogsfcbe[W(&T)Replacement &Text miscdialogsOuYvS(&n)Reserve &numbers miscdialogsh9p Root Node miscdialogsd}"[W{&N2 {0} g*b~R0Search string "{0}" not found miscdialogsd}"eg, {0} g*b~R0Search text "{0}" not found miscdialogs [vRe/(&b)Selected &branches miscdialogs b邂pvT ~p(&s)Selection's &siblings miscdialogs b邂pv[Pp(&n)Selection's childre&n miscdialogs\Vh Small Icons miscdialogsc^eTSort Direction miscdialogsc^el Sort Method miscdialogspc^ Sort Nodes miscdialogsbQhg Spell Check miscdialogs]QwhT}N(&b)Tool&bar Commands miscdialogs]Qwh\:[(&S) Toolbar &Size miscdialogs ]QwhepToolbar Quantity miscdialogs]QwTools miscdialogs]QwSU Tools Menu miscdialogs hV[WOSTree View Font miscdialogs TreeLine - N%͕TreeLine - Serious Error miscdialogsTreeLineSTreeLine Numbering miscdialogsQe {0} v[x:Type Password for "{0}": miscdialogs Qe[x:Type Password: miscdialogs fepSUpdate Node Numbering miscdialogsOu(eNR[(&e)Use file &encryption miscdialogsVView miscdialogsVSU View Menu miscdialogsd}"Q[What to Search miscdialogsc^Q[ What to Sort miscdialogs fevQ[What to Update miscdialogszSWindow miscdialogszSSU Window Menu miscdialogsN QAOu(^[x'Zero-length passwords are not permitted miscdialogs [b@g [Wk] [All Fields] miscdialogs [b@g |{W] [All Types] miscdialogsT [WName nodeformatW( h`P\eom;epcnVh$Activate data editors on mouse hoveroptiondefaultsTHs AppearanceoptiondefaultsRO[X Auto SaveoptiondefaultsRbS_N k!Ou(veN!Automatically open last file usedoptiondefaults[P)POy ([WOS^SUOM)+Child indent offset (in font height units) optiondefaultsSUQpT}T Click node to renameoptiondefaultsepcnVhh<_Data Editor FormatsoptiondefaultsegDatesoptiondefaultsSu(RFeatures Availableoptiondefaults {,NY) kThFirst day of weekoptiondefaultsfgNFridayoptiondefaults.)(ObSSp)TreeLine JSONeN)Indent (pretty print) TreeLine JSON filesoptiondefaultsg\S^u(z ^R0|~bXv#Minimize application to system trayoptiondefaults$O[XNKvRep (N:0hy:yu()+Minutes between saves (set to 0 to disable)optiondefaultsfgNMondayoptiondefaultsgeNvep W(eNSUN-(Number of recent files in the file menuoptiondefaults dm~R+epNumber of undo levelsoptiondefaultsW(ezSN-bS_eNOpen files in new windowsoptiondefaults gveN Recent FilesoptiondefaultsR delՋvgeNgav'Remove inaccessible recent file entriesoptiondefaultsR^eT}T epRename new nodes when createdoptiondefaults`bY N NN*zSQOU Restore previous window geometryoptiondefaults`bY geNvhVr`(Restore tree view states of recent filesoptiondefaultsfgQmSaturdayoptiondefaultsf>y:bS\QyVQHVShow breadcrumb ancestor viewoptiondefaultsW(SbKVN-f>y:[Pzh<#Show child pane in right hand viewsoptiondefaultsW(QVN-f>y:TNShow descendants in output viewoptiondefaultsW(hVN-f>y:VhShow icons in the tree viewoptiondefaultsW(epcnVN-f>y:ep[f[Wk&Show math fields in the Data Edit viewoptiondefaultsW(epcnVN-f>y:S[Wk+Show numbering fields in the Data Edit viewoptiondefaultsT/RgaNStartup ConditionoptiondefaultsfgeSundayoptiondefaultsfgVThursdayoptiondefaultseTimesoptiondefaults hbe>Su(Tree drag && drop availableoptiondefaultsfgNTuesdayoptiondefaultsdmQ[X Undo MemoryoptiondefaultsfgN  Wednesdayoptiondefaults Sm(&C)&Canceloptions xn(&O)&OKoptions bMneNOMn"Choose configuration file locationoptionsz ^v_U(Od:_Ou()$Program directory (for portable use)optionsu(b7vN;v_U(cP)#User's home directory (recommended)optionsRYSbSSpg:eQError initializing printer printdata TreeLine - [QPDFTreeLine - Export PDF printdata,fTJ_SRMbSSpg:N e/c݋n0 O[XetJWarning: Margin settings unsupported on current printer. Save adjustments? printdata:fTJ_SRMbSSpg:N e/cubY'\T݋n0 O[Xubet]Warning: Page size and margin settings unsupported on current printer. Save page adjustments? printdata0fTJ_SRMbSSpg:N e/cubY'\n0 O[XetKWarning: Page size setting unsupported on current printer. Save adjustment? printdata N (&B):&Bottom: printdialogs Sm(&C)&Cancel printdialogs~[Ppu;~(&D)&Draw lines to children printdialogsethh(&E) &Entire tree printdialogs [WOS(&F)&Font printdialogs[WOS b(&F)&Font Selection printdialogs^8Đ y(&G)&General Options printdialogsuw ](&H) &Header Left printdialogsuw /u(&H)&Header/Footer printdialogsSbh9p(&I)&Include root node printdialogs"Oc{,NN*[PpW(r6pN (&K)&Keep first child with parent printdialogs ](&L):&Left: printdialogs Rep(&N)&Number of columns printdialogs xn(&O)&OK printdialogs RM(&P)&Prefix printdialogsbSSp(&P)... &Print... printdialogs S(&R):&Right: printdialogs T(&S)&Suffix printdialogs N (&T):&Top: printdialogs SUOM(&U)&Units printdialogs(Ou(TreeLineQV[WOS(&U)&Use TreeLine output view font printdialogs [(&W):&Width: printdialogs"A3 (279 x 420 mm)A3 (279 x 420 mm) printdialogs"A4 (210 x 297 mm)A4 (210 x 297 mm) printdialogs"A5 (148 x 210 mm)A5 (148 x 210 mm) printdialogs>AaBbCcDdEeFfGg...TtUuVvWvXxYyZzAaBbCcDdEeFfGg...TtUuVvWvXxYyZz printdialogsS|s (cm)Centimeters (cm) printdialogsRColumns printdialogs [NIY'\ Custom Size printdialogs؋[WOS Default Font printdialogsubY'\beeH(Error: Page size or margins are invalid printdialogsYe[W Extra Text printdialogsb[ub Facing Pages printdialogsry_Features printdialogs [Wk(&d)Fiel&ds printdialogs[Wkh<_(&m) Field For&mat printdialogs"{0}"v[Wkh<_Field Format for "{0}" printdialogsTubFit Page printdialogsT[^ Fit Width printdialogs[WOSh7_(&y) Font st&yle printdialogsu(&e):Foot&er: printdialogsu](&L) Footer &Left printdialogsuN-(&n)Footer Ce&nter printdialogsuS(&t) Footer Righ&t printdialogsh<_^.R(&H) Format &Help printdialogsuw (&a):He&ader: printdialogsuw S(&R) Header &Right printdialogsuw N-(&e)Header C&enter printdialogs uw TuHeader and Footer printdialogs:Height: printdialogs [(in) Inches (in) printdialogs SbvpIncluded Nodes printdialogs)Indent printdialogs )POy(&t) (~SUOM)"Indent Offse&t (line height units) printdialogs l4^s(&d) Lan&dscape printdialogs&l_eNf (8.5 x 14 in.)Legal (8.5 x 14 in.) printdialogs"O~ (8.5 x 11 in.)Letter (8.5 x 11 in.) printdialogsMargins printdialogsk|s (mm)Millimeters (mm) printdialogsTNu Next Page printdialogsSg bS_pv[Pp(&y)Onl&y open node children printdialogseT Orientation printdialogsQh<_(&F)Output &Format printdialogsubn(&S) Page &Setup printdialogs~_ \:[(&S) Paper &Size printdialogs zT(&i) Portra&it printdialogsRMNu Previous Page printdialogsbSSpPrint printdialogsbSSp(&v)...Print Pre&view... printdialogsbSSp Print Preview printdialogsbSSpn Print Setup printdialogsbSSpnPrinting Setup printdialogsy:OSample printdialogs bbSSpg:(&P)Select &Printer printdialogs b[WOS Select Font printdialogs [vRe/(&b)Selected &branches printdialogs [vp(&n)Selected &nodes printdialogs \:[(&z)Si&ze printdialogsSUu Single Page printdialogsRNKzzh<(&m)Space between colu&mns printdialogs$\Wb~ (11 x 17 in.)Tabloid (11 x 17 in.) printdialogs TreeLine PDF bSSpg:TreeLine PDF Printer printdialogsbSSpNNH What to print printdialogse>Y'Zoom In printdialogs)\Zoom Out printdialogs mR(&A)&Add spellcheck Sm(&C)&Cancel spellcheck_ueQh(&I) &Ignore All spellcheck fcb(&R)&Replace spellcheckmR\Q(&L)Add &Lowercase spellcheckN N e:Context: spellcheckVb~N R0aspell.exe ispell.exebhunspell.exe c[OMnQCould not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? spellcheck[bhgRe/ NΘv~~3Finished checking the branch Continue from the top? spellcheck [bbQhgFinished spell checking spellcheck _ue(&e)Ignor&e spellcheckH[OMaspell.exe ipsell.exebhunspell.exe-Locate aspell.exe, ipsell.exe or hunspell.exe spellcheck N W([WQxN-Not in Dictionary spellcheckz ^(*.exe)Program (*.exe) spellcheckfcbQh(&p) Re&place All spellcheckbQhg Spell Check spellcheck bQhgSpell Check Error spellcheck^ Suggestions spellcheckTreeLinebQhgTreeLine Spell Check spellcheckTTreeLinebQhg xnO[Naspell ispellbhunspellLTreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed spellcheck:Word: spellcheck W(hN- bSelect in Tree titlelistviewyv{&SBullets treeformats[P|{W ChildType treeformats [P|{WPR6ChildTypeLimit treeformatsgaNRConditionalRule treeformats؋DEFAULT treeformats O0HtmlEvalHtml treeformats[WkFIELD treeformatseNFILE treeformats[Wk|{W FieldType treeformatsh<_Format treeformats h<_Html FormatHtml treeformatsN,|{W GenericType treeformatsVhIcon treeformatsRYP< InitialValue treeformats RhRRr{& ListSeparator treeformatsep[W~NumLines treeformatsQh<_ OutputFormat treeformatsRMPrefix treeformatsTRMc^ SortForward treeformats c^.S SortKeyNum treeformatsN-zzh< SpaceBetween treeformatsTSuffix treeformats|{WTYPE treeformatshh<Table treeformatshh<_ TitleFormat treeformats |OS(&B) &Bold Fonttreelocalcontrol b(&C)&CopytreelocalcontrolR dp(&D) &Delete NodetreelocalcontrolRyQK(&D)&Detach Clonestreelocalcontrol[Q(&E)... &Export...treelocalcontrolYc(&E)...&External Link...treelocalcontrol[WOSY'\(&F) &Font Sizetreelocalcontrol)ۂp(&I) &Indent Nodetreelocalcontrol eOS(&I) &Italic Fonttreelocalcontrol N y(&M)&Move Uptreelocalcontrole^zS(&N) &New Windowtreelocalcontrol |4(&P)&PastetreelocalcontrolbSSp(&P)... &Print...treelocalcontrol PZ(&R)&RedotreelocalcontroleubS€(&R)&Regenerate ReferencestreelocalcontrolT}T (&R)&Renametreelocalcontrol O[X(&S)&Savetreelocalcontrolnp|{W(&S)&Set Node TypetreelocalcontrolbQhg(&S)...&Spell Check...treelocalcontrol dm(&U)&UndotreelocalcontrolSm)ۂp(&U)&Unindent NodetreelocalcontrolmR[Pp(&C) Add &ChildtreelocalcontrolmR|{R+~R+(&L)...Add Category &Level...treelocalcontrol\e[PymRR0 [vr6y Add new child to selected parenttreelocalcontrolmRbOe9YWebc!Add or modify an extrnal web linktreelocalcontrolmRbOe9Q肂pc#Add or modify an internal node linktreelocalcontrollg ^8[Wkelbi\U#Cannot expand without common fieldstreelocalcontrol|{R+[WkCategory Fieldstreelocalcontrolndh<_(&m)Clear For&mattingtreelocalcontrolnd_SRMb [veg,h<_)Clear current or selected text formattingtreelocalcontrolQKb@g S9Mvp(&M)Clone All &Matched NodestreelocalcontrolT^v[WkbSTN&Collapse descendants by merging fieldstreelocalcontrol\b@g S9MvplcbN:QK&Convert all matching nodes into clonestreelocalcontrol\{0}Re/lcbN:QK"Converted {0} branches into clonestreelocalcontrolNeNY R6|{W(&F)...Copy Types from &File...treelocalcontrol\Re/beg,Y R6R0Rj4g(Copy the branch or text to the clipboardtreelocalcontrol$NSNN*TreeLineeNY R6Mn1Copy the configuration from another TreeLine filetreelocalcontrol RjR(&t)Cu&ttreelocalcontrol\Re/beg,RjRR0Rj4g'Cut the branch or text to the clipboardtreelocalcontrol؋Defaulttreelocalcontrol R db@ pDelete the selected nodestreelocalcontrolRy_SRMRe/N-vb@g QKp+Detach all cloned nodes in current branchestreelocalcontrol - elR dYNeN{}'Error - could not delete backup file {}treelocalcontrol - elՋSeN{0}Error - could not read file {0}treelocalcontrol - elQQeeNError - could not write to filetreelocalcontrol - elQQe{}Error - could not write to {}treelocalcontrolNTyQvNh<_[QeN(Export the file in various other formatstreelocalcontrolOu(_SRMbSSp y[QN:PDF+Export to PDF with current printing optionstreelocalcontrol eN]O[X File savedtreelocalcontrolc |{R+bT(&b)Flatten &by Categorytreelocalcontrol[WOSr(&o)...Font C&olor...treelocalcontrol_:R6feb@g gaN|{WTep[f[Wk3Force update of all conditional types & math fieldstreelocalcontrol)ې [vpIndent the selected nodestreelocalcontrolNKTcQeT ~(&A)Insert Sibling &AftertreelocalcontrolNKRMcQeT ~(&B)Insert Sibling &BeforetreelocalcontrolW([PyN ecQe|{R+p$Insert category nodes above childrentreelocalcontrolW( b邂pNKTcQeevT ~p"Insert new sibling after selectiontreelocalcontrolW( b邂pNKRMcQeevT ~p#Insert new sibling before selectiontreelocalcontrolQc(&L)...Internal &Link...treelocalcontrolY'LargetreelocalcontrolfY'LargertreelocalcontrolgY'Largesttreelocalcontrol N y(&o) M&ove DowntreelocalcontrolyR0OM(&F) Move &FirsttreelocalcontrolyR0gT(&L) Move &LasttreelocalcontrolN y [vpMove the selected nodes downtreelocalcontrol\b@ pyRN:{,NN*[Pp0Move the selected nodes to be the first childrentreelocalcontrol\b@ pyRN:gTNN*[Pp/Move the selected nodes to be the last childrentreelocalcontrolN y [vpMove the selected nodes uptreelocalcontrolb~N R0vT vpNo identical nodes foundtreelocalcontrolbS_T NeNvezS#Open a new window for the same filetreelocalcontrolbSSpn(&r)...P&rint Setup...treelocalcontrol|4~eg,(&s)Pa&ste Plain Texttreelocalcontrol|4[Pp(&h) Paste C&hildtreelocalcontrol|4QKv[Pp(&o)Paste Cl&oned ChildtreelocalcontrolNKRM|4QKvT ~(&n)Paste Clo&ned Sibling BeforetreelocalcontrolNKT|4QKvT ~(&d)Paste Clone&d Sibling AftertreelocalcontrolNKT|4T ~(&A)Paste Sibling &AftertreelocalcontrolNKRM|4T ~(&B)Paste Sibling &BeforetreelocalcontrolNRj4g|4QKv[Pp&Paste a child clone from the clipboardtreelocalcontrolNRj4g|4[Pp%Paste a child node from the clipboardtreelocalcontrolW( b邂pNKT|4evT ~pPaste a sibling after selectiontreelocalcontrolW( b邂pNKRM|4evT ~p Paste a sibling before selectiontreelocalcontrol"W( b邂pNKT|4evT ~QKp%Paste a sibling clone after selectiontreelocalcontrol"W( b邂pNKRM|4evT ~QKp&Paste a sibling clone before selectiontreelocalcontrol|4Rj4gN-vpbeg,&Paste nodes or text from the clipboardtreelocalcontrolNRj4g|4g*h<_Sveg,+Paste non-formatted text from the clipboardtreelocalcontrolbSSpR0PDF(&t)...Print &to PDF...treelocalcontrolbSSp(&v)...Print Pre&view...treelocalcontrolh9cn_SRM ybSSphQ*Print tree output based on current optionstreelocalcontrol\^`'(&e)...Prop&erties...treelocalcontrolPZN NN*dmRedo the previous undotreelocalcontrolT}T _SRMhgavh#Rename the current tree entry titletreelocalcontrolNcb|{R+~R+(&w)S&wap Category LevelstreelocalcontrolS[XN:(&A)... Save &As...treelocalcontrolO[XeN Save Filetreelocalcontrol\fe9O[XR0{}Save changes to {}?treelocalcontrol O[Xfe9 Save changes?treelocalcontrol O[X_SRMeNSave the current filetreelocalcontrolOu(eT yO[XeNSave the file with a new nametreelocalcontrol be~R+v[WkSelect fields for new leveltreelocalcontrol n[WOSY'\ Set Font Sizetreelocalcontrol np|{W Set Node TypetreelocalcontrolnS)TR[{IeNSep3Set file parameters like compression and encryptiontreelocalcontrol n ubY'\TQvNbSSp y1Set margins, page size and other printing optionstreelocalcontroln_SRMbb@ eg,vY'\(Set size of the current or selected texttreelocalcontroln_SRMbb@ eg,vr-Set the color of the current or selected texttreelocalcontrol\_SRMb [v[WOSnN:|OS(Set the current or selected font to boldtreelocalcontrol\_SRMb [v[WOSnN:eOS*Set the current or selected font to italictreelocalcontrol\_SRMb [v[WOSnN:N R~-Set the current or selected font to underlinetreelocalcontrolnb@ pvp|{W$Set the node type for selected nodestreelocalcontrolf>y:bSSp~gv"Show a preview of printing resultstreelocalcontrol\SmalltreelocalcontrolbQhghveg,epcn Spell check the tree's text datatreelocalcontrolNcb[PpT[Yp|{p(Swap child and grandchild category nodestreelocalcontrol$TreeLine - bS_MneN"TreeLine - Open Configuration FiletreelocalcontrolTreeLine - S[XN:TreeLine - Save AstreelocalcontrolN R~(&n)U&nderline FonttreelocalcontroldmN NN*dO\Undo the previous actiontreelocalcontrolSm)ې [vpUnindent the selected nodestreelocalcontrol2fTJ - eNc_WO W(NN pN-NWO[P_u(OWarning - file corruption! Skipped bad child references in the following nodes:treelocalcontrol"QsNTreeLine(&A)...&About TreeLine...treemaincontrolWg,u(l(&B)...&Basic Usage...treemaincontrolSmeNbS_(&C)&Cancel File OpentreemaincontrolgaNgb~(&C)...&Conditional Find...treemaincontrolMnepcn|{W(&C)...&Configure Data Types...treemaincontrolR dYN(&D)&Delete Backuptreemaincontrolgb~eg,(&F)... &Find Text...treemaincontrol[etehc(&F)...&Full Documentation...treemaincontrol^8Đ y(&G)...&General Options...treemaincontrol[Qe(&I)... &Import...treemaincontrole^(&N)...&New...treemaincontrolbS_(&O)...&Open...treemaincontrol Q(&Q)&Quittreemaincontrol`bY YN(&R)&Restore Backuptreemaincontrol bb@g (&S) &Select Alltreemaincontrol by:OeN(&S)&Select Sampletreemaincontrol bj!g(&S)&Select Templatetreemaincontroleg,nVh(&T)...&Text Filter...treemaincontrol.YNeN {} [XW(0 NKRMvOS]~])ny:Wg,Ou(f Display basic usage instructionstreemaincontrolf>y:g Qskdz ^vrHg,O`o'Display version info about this programtreemaincontrol - b~N R0Wg,^.ReN!Error - basic help file not foundtreemaincontrol - elՋSeN{0}Error - could not read file {0}treemaincontrol - elR dYNeN{}'Error - could not remove backup file {}treemaincontrol, - el\ {0} T}T N: {1} 'Error - could not rename "{0}" to "{1}"treemaincontrol  - el\MneNQQe{})Error - could not write config file to {}treemaincontrol - b~N R0ehceN$Error - documentation file not foundtreemaincontrol* - eeHvTreeLineeN{0}!Error - invalid TreeLine file {0}treemaincontrolQ^u(Exit the applicationtreemaincontroln䂂pNf>y:S9Meg,&Filter nodes to only show text matchestreemaincontrolgb~Tfcb(&R)...Find and &Replace...treemaincontrolW(hTepcnN-gb~eg,Find text in node titles & datatreemaincontrol^8Đ yGeneral Optionstreemaincontrol^rHg,:Library versions:treemaincontrolepcn|{W [WkTQL(Modify data types, fields & output linestreemaincontroleeNNew FiletreemaincontrolbS_eN Open FiletreemaincontrolbS_y:OeN(&m)...Open Sa&mple...treemaincontrol bS_y:OeN Open SampletreemaincontrolbS_NN*y:OeNOpen Sample Filetreemaincontrol$Ou([etehcbS_TreeLineeN,Open a TreeLine file with full documentationtreemaincontrolNxvN bS_eNOpen a file from disktreemaincontrolbS_NN*^TreeLineeNOpen a non-TreeLine filetreemaincontrolbS_NN*y:OeNOpen a sample filetreemaincontrolfcbpepcnN-veg,[W{&N2!Replace text strings in node datatreemaincontrolW(Vh̐ bb@g Select all text in an editortreemaincontroln.v_cw.(&K)...Set &Keyboard Shortcuts...treemaincontrolnb@g eNvu(b7 y"Set user preferences for all filestreemaincontrolf>y:Mn~g(&o)... Show C&onfiguration Structure...treemaincontrolf>y:Sv|{W~gSS.Show read-only visualization of type structuretreemaincontrolpc^(&t)...Sor&t Nodes...treemaincontrol_YNN*eeNStart a new filetreemaincontrolTreeLine - bS_eNTreeLine - Open FiletreemaincontrolTreeLineWg,u(lTreeLine Basic UsagetreemaincontrolTreeLinerHg,{0}TreeLine version {0}treemaincontrolfeS(&N)...Update &Numbering...treemaincontrolfepepPy:[Pzh<(&S)&Show Child Pane treewindow ]Qw(&T)&Tools treewindow V(&V)&View treewindow zS(&W)&Window treewindow QsN*zSClose this window treewindowbS [pvb@g [Pp+Collapse all children of the selected nodes treewindowepcn Data Edit treewindowepcnQ Data Output treewindow\U_ [pvb@g [Pp)Expand all children of the selected nodes treewindow h<_(&r)Fo&rmat treewindowSR0N NN*SSh b(Go to the next tree selection in history treewindowN NN*Xd}"Next Incremental Search treewindowN NN*Xd}"Previous Incremental Search treewindowVN NN*h b%Return to the previous tree selection treewindowf>y:bS\QV(&B)Show &Breadcrumb View treewindowf>y:hRh(&T)Show &Title List treewindowf>y:epcnVh(&E)Show Data &Editor treewindowf>y:epcnQ(&O)Show Data &Output treewindowf>y:QTN(&D)Show Output &Descendants treewindowW(SOVf>y:epcnVhShow data editor in right view treewindowW(SOVf>y:epcnQShow data output in right view treewindowW(SOVf>y:hRhShow title list in right view treewindow _YXd}"Start Incremental Search treewindowhRh Title List treewindowRcbf>y:bS\QyVV'Toggle showing breadcrumb ancestor view treewindowRcbf>y:QV)TN/Toggle showing output view indented descendants treewindowRcbf>y:SO[PV%Toggle showing right-hand child views treewindowTreeLine-3.2.1/treeline.desktop000066400000000000000000000003511506556630100164340ustar00rootroot00000000000000[Desktop Entry] Type=Application Version=1.1 Name=TreeLine GenericName=Outliner Comment=Organize text information in a tree structure Exec=treeline %f Icon=treeline-icon StartupNotify=true Terminal=false Categories=Office;TextTools; TreeLine-3.2.1/uninstall.py000077500000000000000000000052761506556630100156330ustar00rootroot00000000000000#!/usr/bin/env python """ **************************************************************************** uninstall.py, Linux uninstall script for TreeLine Copyright (C) 2018, Douglas W. Bell This is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, either Version 2 or any later version. This program is distributed in the hope that it will be useful, but WITTHOUT ANY WARRANTY. See the included LICENSE file for details. ***************************************************************************** """ import sys import os.path import getopt import shutil prefixDir = '/usr/local' progName = 'treeline' def usage(exitCode=2): """Display usage info and exit. Arguments: exitCode -- the code to retuen when exiting. """ global prefixDir print('Usage:') print(' python uninstall.py [-h] [-p dir]') print('where:') print(' -h display this help message') print(' -p dir install prefix [default: {0}]'.format(prefixDir)) sys.exit(exitCode) def removeAll(path): """Remove path, whether it is a file or a directory, print status""" print(' Removing {0}...'.format(path)) try: if os.path.isdir(path): shutil.rmtree(path) elif os.path.isfile(path): os.remove(path) else: print(' not found') return print(' done') except OSError as e: if str(e).find('Permission denied') >= 0: print('\nError - must be root to remove files') sys.exit(4) raise def main(): """Main uninstaller function. """ try: opts, args = getopt.getopt(sys.argv[1:], 'hp:') except getopt.GetoptError: usage(2) global prefixDir for opt, val in opts: if opt == '-h': usage(0) elif opt == '-p': prefixDir = val print('Removing files...') global progName removeAll(os.path.join(prefixDir, 'lib', progName)) removeAll(os.path.join(prefixDir, 'share', 'doc', progName)) removeAll(os.path.join(prefixDir, 'share', progName)) removeAll(os.path.join(prefixDir, 'share', 'icons', progName)) removeAll(os.path.join(prefixDir, 'share', 'icons', 'hicolor', '48x48', 'apps', progName + '-icon.png')) removeAll(os.path.join(prefixDir, 'share', 'icons', 'hicolor', 'scalable', 'apps', progName + '-icon.svg')) removeAll(os.path.join(prefixDir, 'share', 'applications', progName + '.desktop')) removeAll(os.path.join(prefixDir, 'bin', progName)) print('Uninstall complete.') if __name__ == '__main__': main() TreeLine-3.2.1/win/000077500000000000000000000000001506556630100140305ustar00rootroot00000000000000TreeLine-3.2.1/win/treeline-all.iss000066400000000000000000000102341506556630100171250ustar00rootroot00000000000000; treeline-all.iss ; Inno Setup installer script for Treeline, an information storage program. ; This will install for a all users, admin rights are required. [Setup] AppName=TreeLine AppVersion=3.2.1 ChangesAssociations=yes DefaultDirName={commonpf}\TreeLine-3 DefaultGroupName=TreeLine DisableProgramGroupPage=yes OutputDir=. OutputBaseFilename=treeline-3.2.1-install-all PrivilegesRequired=poweruser SetupIconFile=treeline.ico Uninstallable=WizardIsTaskSelected('adduninstall') UninstallDisplayIcon={app}\treeline.exe,0 [Tasks] Name: "fileassoc"; Description: "Add *.trln file association" Name: "startmenu"; Description: "Add start menu shortcuts" Name: "deskicon"; Description: "Add a desktop shortcut" Name: "adduninstall"; Description: "Create an uninstaller" Name: "translate"; Description: "Include language translations" Name: "source"; Description: "Include source code" [InstallDelete] Type: files; Name: "{app}\library.zip" Type: files; Name: "{app}\python*.zip" Type: files; Name: "{app}\*.pyd" Type: files; Name: "{app}\*.dll" Type: files; Name: "{app}\doc\documentation.trl" Type: filesandordirs; Name: "{app}\lib" Type: filesandordirs; Name: "{app}\imageformats" Type: filesandordirs; Name: "{app}\platforms" Type: dirifempty; Name: "{app}\plugins" Type: files; Name: "{app}\samples\*.trl" Type: files; Name: "{app}\source\*.py" Type: files; Name: "{app}\templates\*.trl" Type: files; Name: "{app}\translations\*.qm" [Files] Source: "treeline.exe"; DestDir: "{app}" Source: "base_library.zip"; DestDir: "{app}" Source: "*.dll"; DestDir: "{app}" Source: "*.pyd"; DestDir: "{app}" Source: "PyQt6\*"; DestDir: "{app}\PyQt6"; Flags: recursesubdirs Source: "doc\LICENSE"; DestDir: "{app}\doc" Source: "doc\basichelp.html"; DestDir: "{app}\doc" Source: "doc\documentation.trln"; DestDir: "{app}\doc"; Attribs: readonly; \ Flags: overwritereadonly uninsremovereadonly Source: "doc\*.html"; DestDir: "{app}\doc"; Tasks: "translate" Source: "doc\*.trln"; DestDir: "{app}\doc"; Attribs: readonly; \ Tasks: "translate"; Flags: overwritereadonly uninsremovereadonly Source: "samples\*.trln"; DestDir: "{app}\samples"; Attribs: readonly; \ Flags: overwritereadonly uninsremovereadonly Source: "icons\toolbar\32x32\*.png"; DestDir: "{app}\icons\toolbar\32x32" Source: "icons\tree\*.png"; DestDir: "{app}\icons\tree" Source: "templates\exports\*.*"; DestDir: "{app}\templates\exports" Source: "templates\*en_*.trln"; DestDir: "{app}\templates"; Attribs: readonly; \ Flags: overwritereadonly uninsremovereadonly Source: "templates\*.trln"; DestDir: "{app}\templates"; Attribs: readonly; \ Tasks: "translate"; Flags: overwritereadonly uninsremovereadonly Source: "translations\*.qm"; DestDir: "{app}\translations"; Tasks: "translate" Source: "source\*.py"; DestDir: "{app}\source"; Tasks: "source" Source: "source\treeline.pro"; DestDir: "{app}\source"; Tasks: "source" Source: "source\treeline.spec"; DestDir: "{app}\source"; Tasks: "source" Source: "treeline.ico"; DestDir: "{app}"; Tasks: "source" Source: "*.iss"; DestDir: "{app}"; Tasks: "source" [Icons] Name: "{commonstartmenu}\TreeLine 3"; Filename: "{app}\treeline.exe"; \ WorkingDir: "{app}"; Tasks: "startmenu" Name: "{group}\TreeLine 3"; Filename: "{app}\treeline.exe"; \ WorkingDir: "{app}"; Tasks: "startmenu" Name: "{group}\Uninstall"; Filename: "{uninstallexe}"; Tasks: "startmenu" Name: "{commondesktop}\TreeLine 3"; Filename: "{app}\treeline.exe"; \ WorkingDir: "{app}"; Tasks: "deskicon" [Registry] Root: HKCR; Subkey: ".trln"; ValueType: string; \ ValueName: ""; ValueData: "TreeLineFile"; Flags: uninsdeletevalue; \ Tasks: "fileassoc" Root: HKCR; Subkey: "TreeLineFile"; ValueType: \ string; ValueName: ""; ValueData: "TreeLine File"; \ Flags: uninsdeletekey; Tasks: "fileassoc" Root: HKCR; Subkey: "TreeLineFile\DefaultIcon"; \ ValueType: string; ValueName: ""; ValueData: "{app}\treeline.exe,0"; \ Tasks: "fileassoc" Root: HKCR; Subkey: "TreeLineFile\shell\open\command"; \ ValueType: string; ValueName: ""; \ ValueData: """{app}\treeline.exe"" ""%1"""; Tasks: "fileassoc" TreeLine-3.2.1/win/treeline-user.iss000066400000000000000000000103431506556630100173340ustar00rootroot00000000000000; treeline-user.iss ; Inno Setup installer script for Treeline, an information storage program. ; This will install for a single user, no admin rights are required. [Setup] AppName=TreeLine AppVersion=3.2.1 ChangesAssociations=yes DefaultDirName={userappdata}\TreeLine-3 DefaultGroupName=TreeLine DisableProgramGroupPage=yes OutputDir=. OutputBaseFilename=treeline-3.2.1-install-user PrivilegesRequired=lowest SetupIconFile=treeline.ico Uninstallable=WizardIsTaskSelected('adduninstall') UninstallDisplayIcon={app}\treeline.exe,0 [Tasks] Name: "fileassoc"; Description: "Add *.trln file association" Name: "startmenu"; Description: "Add start menu shortcuts" Name: "deskicon"; Description: "Add a desktop shortcut" Name: "adduninstall"; Description: "Create an uninstaller" Name: "translate"; Description: "Include language translations" Name: "source"; Description: "Include source code" [InstallDelete] Type: files; Name: "{app}\library.zip" Type: files; Name: "{app}\python*.zip" Type: files; Name: "{app}\*.pyd" Type: files; Name: "{app}\*.dll" Type: files; Name: "{app}\doc\documentation.trl" Type: filesandordirs; Name: "{app}\lib" Type: filesandordirs; Name: "{app}\imageformats" Type: filesandordirs; Name: "{app}\platforms" Type: dirifempty; Name: "{app}\plugins" Type: files; Name: "{app}\samples\*.trl" Type: files; Name: "{app}\source\*.py" Type: files; Name: "{app}\templates\*.trl" Type: files; Name: "{app}\translations\*.qm" [Files] Source: "treeline.exe"; DestDir: "{app}" Source: "base_library.zip"; DestDir: "{app}" Source: "*.dll"; DestDir: "{app}" Source: "*.pyd"; DestDir: "{app}" Source: "PyQt6\*"; DestDir: "{app}\PyQt6"; Flags: recursesubdirs Source: "doc\LICENSE"; DestDir: "{app}\doc" Source: "doc\basichelp.html"; DestDir: "{app}\doc" Source: "doc\documentation.trln"; DestDir: "{app}\doc"; Attribs: readonly; \ Flags: overwritereadonly uninsremovereadonly Source: "doc\*.html"; DestDir: "{app}\doc"; Tasks: "translate" Source: "doc\*.trln"; DestDir: "{app}\doc"; Attribs: readonly; \ Tasks: "translate"; Flags: overwritereadonly uninsremovereadonly Source: "samples\*.trln"; DestDir: "{app}\samples"; Attribs: readonly; \ Flags: overwritereadonly uninsremovereadonly Source: "icons\toolbar\32x32\*.png"; DestDir: "{app}\icons\toolbar\32x32" Source: "icons\tree\*.png"; DestDir: "{app}\icons\tree" Source: "templates\exports\*.*"; DestDir: "{app}\templates\exports" Source: "templates\*en_*.trln"; DestDir: "{app}\templates"; Attribs: readonly; \ Flags: overwritereadonly uninsremovereadonly Source: "templates\*.trln"; DestDir: "{app}\templates"; Attribs: readonly; \ Tasks: "translate"; Flags: overwritereadonly uninsremovereadonly Source: "translations\*.qm"; DestDir: "{app}\translations"; Tasks: "translate" Source: "source\*.py"; DestDir: "{app}\source"; Tasks: "source" Source: "source\treeline.pro"; DestDir: "{app}\source"; Tasks: "source" Source: "source\treeline.spec"; DestDir: "{app}\source"; Tasks: "source" Source: "treeline.ico"; DestDir: "{app}"; Tasks: "source" Source: "*.iss"; DestDir: "{app}"; Tasks: "source" [Icons] Name: "{userstartmenu}\TreeLine 3"; Filename: "{app}\treeline.exe"; \ WorkingDir: "{app}"; Tasks: "startmenu" Name: "{group}\TreeLine 3"; Filename: "{app}\treeline.exe"; \ WorkingDir: "{app}"; Tasks: "startmenu" Name: "{group}\Uninstall"; Filename: "{uninstallexe}"; Tasks: "startmenu" Name: "{userdesktop}\TreeLine 3"; Filename: "{app}\treeline.exe"; \ WorkingDir: "{app}"; Tasks: "deskicon" [Registry] Root: HKCU; Subkey: "Software\Classes\.trln"; ValueType: string; \ ValueName: ""; ValueData: "TreeLineFile"; Flags: uninsdeletevalue; \ Tasks: "fileassoc" Root: HKCU; Subkey: "Software\Classes\TreeLineFile"; ValueType: \ string; ValueName: ""; ValueData: "TreeLine File"; \ Flags: uninsdeletekey; Tasks: "fileassoc" Root: HKCU; Subkey: "Software\Classes\TreeLineFile\DefaultIcon"; \ ValueType: string; ValueName: ""; ValueData: "{app}\treeline.exe,0"; \ Tasks: "fileassoc" Root: HKCU; Subkey: "Software\Classes\TreeLineFile\shell\open\command"; \ ValueType: string; ValueName: ""; \ ValueData: """{app}\treeline.exe"" ""%1"""; Tasks: "fileassoc" TreeLine-3.2.1/win/treeline.ico000066400000000000000000000353561506556630100163470ustar00rootroot00000000000000 h6  00 %F(  m}@pbs$Es?p[o;lIaSi;lH`asѭ;lH`bs׺Mˢ;lH`bsMx Qھl&b;lG`ct?pEtlp;lG`\oQcu&Gt;lIb2Qzn};l;l Bq$Fs;l Bq&Gt&Gt&Gt=m;lpKKϨֶKKwÑ;l;lcuy:l:lKKXϨKKЫſ;l;lbty:l:l PK6kAdBdľ;l;lbtx:l:lCg=c~Wz;l;lYm¼;l;latx:l:l7S};l;lJc;l;l;lew;l;lat@Z;l;lTj;l;l;l;l;lBq5R|5R|-Lw;l;l Bq5R|5R|5R|5R|5R|5R|5R|,Kw;l;l;l;l^r;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;lhy+j ca-j-jyKKEt׺KKŖ'bKPɝKKϪƖKK-Lw;l;l)Iv;XMd_r{hySi@Z-Kw>n:l:l:l:l:l:l3PzOf;l;l;l;l;l:l:l:l:l:l:l:l:l:ln;l;l;l;l:l:l:l:l;l;l;lXl;l;l;l;l;l;l;l;l:l:l:l:liyVl;l;l;lbt;l;l;l;l&Gt;l;l;l;l=m;l;l;lk{@p;l;l;l;l$Fs;l;l;l;l1Py;l;l;l;lu(Hv;l;l;l;l;l;l;l(Hv5R|A[E^E^1Py;l;l;l;l7T}E^E^E^E^E^E^E^E^QhLc@Z?o;l;l;l;l;l;l3Qz;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l>Z;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l;l[2p,m(j|V4q:t@wR{KKKȜ1hKKKӰpKKKW~XKKKڿӰKKKUKKKKNKKKwÑϪKKK ^`KKKKlʞ,eKpKKK!^~ұ RKKKKKKKKKKKKԳŖKKKKˠ|/t\KKKKL$`VKKK RǘKKKK/f,үKKKK RұHvKKKKN=mKKKKK@pӰҮV~MKKKKMѭ@S|KKKKKKKKKKKKKKKNЫqKKKKKKKKKKKKK%a ׷.fKKKKKKKKKXǚүS|KKXXЬ8@.}|-TreeLine-3.2.1/working/000077500000000000000000000000001506556630100147135ustar00rootroot00000000000000TreeLine-3.2.1/working/translations/000077500000000000000000000000001506556630100174345ustar00rootroot00000000000000TreeLine-3.2.1/working/translations/gettrans.py000077500000000000000000000241631506556630100216460ustar00rootroot00000000000000#!/usr/bin/env python3 #****************************************************************************** # gettrans.py, updates Qt-style translation files from PyQt source # uses gettext-style markings and filenames as contexts # # Copyright (C) 2020, Douglas W. Bell # # This is free software; you can redistribute it and/or modify it under the # terms of the GNU General Public License, either Version 2 or any later # version. This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. See the included LICENSE file for details. #****************************************************************************** import argparse import pathlib import ast import collections import copy import xml.etree.ElementTree as ET from xml.sax.saxutils import escape class TransItem: """Class to hold data for and output a single translation string. """ def __init__(self, contextName, lineNum, srcText, comment=''): """Initialize the tramslation string item. Arguments: contextName -- a string containing the filename-based context lineNum -- the line of the first occurrence in the source code srcText -- the untranslated source text string comment -- optional comment from source as a guide to translation """ self.contextName = contextName self.lineNum = lineNum self.srcText = srcText self.comment = comment self.transType = 'unfinished' self.transText = '' def xmlLines(self): """Return a list of XML output lines for this item. """ lines = [' ', f' ', f' {escape(self.srcText)}'] if self.comment: lines.append(f' {self.comment}') transType = f' type="{self.transType}"' if self.transType else '' lines.extend([f' ' f'{escape(self.transText)}', ' ']) return lines def readSource(path, sourceDict): """Read strings to be translated from the a single source file path. Updates the give source dict with any results from this context. Arguments: path -- the source file path to read sourceDict -- the dictionary to add a context dict to with results """ with path.open(encoding='utf-8') as f: src = f.read() tree = ast.parse(src) contextDict = collections.OrderedDict() for node in ast.walk(tree): if (isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and (node.func.id == '_' or node.func.id == 'N_')): try: text = node.args[0].value text.replace # throw exception if not a string comment = node.args[1].value if len(node.args) > 1 else '' except AttributeError: continue # skip if no string is present item = TransItem(path.stem, node.lineno, text, comment) contextDict.setdefault((text, comment), item) if contextDict: # only add the context dictionary if there are results sourceDict[path.stem] = contextDict if verbose: print('Read', len(contextDict), 'items from', path.name) def readXml(root, sourceDict, keepObsolete=True): """Read the XML for a language file starting from an elemant tree root. Returns tuple of an outputDict with results by context and a globalDict with all translations to search for matches. Arguments: root -- the ET root to read sourceDict -- the dict with source strings for comparison keepObsolete -- save obsolete strings (no longer in source) if True """ outputDict = collections.OrderedDict() globalDict = {} for contextNode in root.findall('context'): contextName = contextNode.find('name').text currentDict = collections.OrderedDict() numObsolete = 0 for msgNode in contextNode.findall('message'): try: lineNum = int(msgNode.find('location').attrib['line']) except AttributeError: # .ts files converted from .qm files have no locations and # line numbers lineNum = 0 srcText = msgNode.find('source').text commentNode = msgNode.find('comment') comment = commentNode.text if commentNode is not None else '' item = TransItem(contextName, lineNum, srcText, comment) transNode = msgNode.find('translation') item.transType = transNode.attrib.get('type', '') item.transText = transNode.text if transNode.text else '' try: sourceItem = sourceDict[contextName][(srcText, comment)] except KeyError: # string wasn't found in source dict if item.transType != 'obsolete': item.transType = 'obsolete' numObsolete += 1 else: item.lineNum = sourceItem.lineNum if item.transType == 'obsolete': item.transType = 'unfinished' if keepObsolete or item.transType != 'obsolete': currentDict[(srcText, comment)] = item if item.transText: globalDict[(srcText, comment)] = item outputDict[contextName] = currentDict if verbose and numObsolete: print(f' {numObsolete} newly obsolete strings in ' f'{contextName}.py') return (outputDict, globalDict) def addMissingItems(sourceDict, outputDict): """Add items from source dict that are missing from output dict. Arguments: sourceDict -- the source translations to add from outputDict -- the result dict to modify """ for contextName, sourceItems in sourceDict.items(): numNew = 0 currentDict = outputDict.get(contextName, {}) if not currentDict: outputDict[contextName] = currentDict for sourceItem in sourceItems.values(): if (verbose and (sourceItem.srcText, sourceItem.comment) not in currentDict): numNew += 1 currentDict.setdefault((sourceItem.srcText, sourceItem.comment), copy.copy(sourceItem)) if verbose and numNew: print(f' {numNew} new strings added from {contextName}.py') def updateFromGlobal(outputDict, globalDict): """Search strings from all contexts and add translations if they match. Arguments: outputDict -- the result dict to modify globalDict -- the overall dict to search """ for contextName, currentDict in outputDict.items(): numUpdates = 0 for item in currentDict.values(): if not item.transText: match = globalDict.get((item.srcText, item.comment)) if match: item.transText = match.transText numUpdates += 1 if verbose and numUpdates: print(f' {numUpdates} translations in {contextName} copied ' 'from other strings') def outputXml(outputDict, path, lang): """Return a list of output lines for a language file. Arguments: outputDict -- the result strings to output path -- the translation file path to write the file lang -- the language code for the file header """ outputLines = ['', f''] for contextName, currentDict in outputDict.items(): outputLines.extend(['', f' {contextName}']) for item in currentDict.values(): outputLines.extend(item.xmlLines()) outputLines.append('') outputLines.append('') with open(path, 'w', encoding='utf-8') as f: f.write('\n'.join(outputLines)) verbose = False def main(): """Main program entry function. """ parser = argparse.ArgumentParser() parser.add_argument('sourceDir', type=pathlib.Path, help='directory of input source files read with *.py') parser.add_argument('translateDir', type=pathlib.Path, help='directory of *.ts translation files to update') parser.add_argument('--no-obsolete', action='store_true', help='drop all obsolete strings') parser.add_argument('-R', '--recursive', action='store_true', help='recursively scan the directories') parser.add_argument('-v', '--verbose', action='store_true', help='increase output messages') args = parser.parse_args() global verbose verbose = args.verbose sourceDict = collections.OrderedDict() pyGlob = '**/*.py' if args.recursive else '*.py' for sourcePath in sorted(args.sourceDir.glob(pyGlob)): readSource(sourcePath, sourceDict) if verbose: print('-----------------------------------------') tsGlob = '**/*.ts' if args.recursive else '*.ts' for transPath in sorted(args.translateDir.glob(tsGlob)): try: root = ET.parse(transPath).getroot() except ET.ParseError: print('Warning: nothing read from', transPath) root = ET.ElementTree(ET.Element('TS')).getroot() lang = root.attrib.get('language') if not lang: # get from filename if not in header pathParts = transPath.stem.split('_') if len(pathParts) > 1: lang = pathParts[-1] if not lang: lang = 'xx' if verbose: print(f'For language code "{lang}":') outputDict, globalDict = readXml(root, sourceDict, not args.no_obsolete) addMissingItems(sourceDict, outputDict) updateFromGlobal(outputDict, globalDict) outputXml(outputDict, transPath, lang) if __name__ == '__main__': """Main program entry point. """ main() TreeLine-3.2.1/working/translations/treeline_de.ts000066400000000000000000005713401506556630100222750ustar00rootroot00000000000000 conditional starts with beginnt mit ends with endet mit contains enthält True Wahr False Falsch and und or oder [All Types] [Alle Typen] Node Type Knotentyp &Add New Rule &Regel hinzufügen &Remove Rule &Regel löschen &OK &OK &Cancel &Abbrechen Find &Previous Suche &Vorherigen Find &Next Suche &Nächsten &Filter &Filter &End Filter Filter &beenden &Close &Schließen No conditional matches were found Keine Übereinstimmungen gefunden Rule {0} Regel {0} Saved Rules Gespeicherte Regeln Name: Name: &Load &Laden &Save S&peichern &Delete &Löschen configdialog Configure Data Types Datentypen konfigurieren T&ype List &Typliste Field &List &Feldliste &Field Config Feld &konfigurieren &Show Advanced Erweitert &anzeigen &OK &OK &Apply &Anwenden &Reset &Zurücksetzen &Cancel &Abbrechen Add or Remove Data Types Datentypen hinzufügen oder löschen &New Type... &Neuer Typ... Co&py Type... Typ &kopieren... &Delete Type Typ &löschen Add Type Typ hinzufügen Enter new type name: Gib den Namen des neuen Typs ein: Rename Type Typ umbenennen Cannot delete data type being used by nodes Kann keinen Datentyp löschen, der noch in Benutzung ist &Data Type &Datentyp Icon Icon Change &Icon &Icon ändern Derived from &Generic Type Abgeleitet von &Basistyp Automatic Types Automatische Typen Modify Co&nditional Types &Bedingte Typen ändern Create Co&nditional Types &Bedingte Typen anlegen Set Types Conditionally Typ durch Bedingung setzen Name Name Type Typ Move &Up Nach &oben verschieben Move Do&wn Nach &unten verschieben &New Field... &Neues Feld... Add Field Feld hinzufügen Enter new field name: Name des neuen Feldes eingeben: Rename Field Feld umbenennen F&ield &Feld Format &Help Hilfe zum &Format Extra Text Zusatztext &Prefix &Präfix Suffi&x &Suffix Editor Height Editorhöhe Num&ber of text lines &Anzahl der Textzeilen File Info Reference Dateiinfo-Verweis Parent Reference Vater-Verweis Child Reference Kind-Verweis Child Count Anzahl Kinder F&ield List &Feldliste Other Field References Verweise zu anderen Feldern Copy Type Typ kopieren Set Data Type Icon Datentyp Icon zuweisen Clear &Select Auswahl &zurücksetzen Typ&e Config Typ &Konfiguration O&utput &Ausgabe &Hide Advanced Erweitert &ausblenden Error - circular reference in math field equations Fehler - Zirkulärer Verweis im berechnetem Feld Rena&me Type... Typ &umbenennen... &Derive from original Von &Original ableiten Rename from {} to: Umbenennen von {} nach: [None] no type set [Leer] Default Child &Type Standard Kind &Typ Output Options Ausgabeoptionen Add &blank lines between nodes &Leere Zeilen zwischen Knotenhinzufügen Allow &HTML rich text in format &HTML Text im Format erlauben Add text bullet&s &Aufzählungspunkte hinzufügen Use a table for field &data Eine Tabelle für &Feldwerte verwenden Combination && Child List Output &Separator Ausgabe &Trenner für Kombination && Kindliste None Leer Modify &Field List &Feldliste bearbeiten Sort Key Sortierfeld Move U&p Nach &oben verschieben Rena&me Field... Feld &umbenennen... Dele&te Field Feld &löschen Sort &Keys... &Sortierfelder... fwd >> rev << &Field Type &Feldtyp Outpu&t Format &Ausgabeformat Default &Value for New Nodes &Standardwert für neue Knoten Math Equation Mathematischer Ausdruck Define Equation Ausdruck definieren &Title Format &Überschrift Format Out&put Format &Ausgabeformat Reference Le&vel Verweis&stufe Refere&nce Type Verweis&typ The name cannot be empty Der Name kann nicht leer sein The name must start with a letter Der Name muss mit einem Buchstaben beginnen The name cannot start with "xml" Der Name kann nicht mit "xml" beginnen The name cannot contain spaces Der Name darf keine Leerzeichen enthalten The following characters are not allowed: {} Die folgenden Zeichen sind nicht erlaubt: {} The name was already used Der Name ist bereits in Verwendung forward vorwärts reverse rückwärts Sort Key Fields Sortierfelder Available &Fields Verfügbare &Felder &Sort Criteria &Sortierbedingung Field Feld Direction Richtung &Move Down Nach &unten Flip &Direction Richtung &umkehren Self Reference Verweis auf sich selbst Root Reference Verweis auf Wurzel Date Result Datum Time Result Uhrzeit add hinzufügen subtract abziehen multiply multiplizieren divide dividieren floor divide dividieren mit runden modulus modulo power exponieren sum of items summieren maximum Maximum minimum Minimum average Durchschnitt absolute value Absolutwert square root Quadratwurzel natural logarithm Natürlicher Logarithmus base-10 logarithm Logarithmus Basis 10 factorial Fakultät round to num digits Runden auf n Stellen lower integer Niedrigere Ganzzahl higher integer Höhere Ganzzahl truncated integer Abgeschnittene Ganzzahl floating point Fliesskommazahl sine of radians Sinus Bogenmaß cosine of radians Cosinus Bogenmaß tangent of radians Tangens Bogenmaß arc sine Arcus Sinus arc cosine Arcus Cosinus arc tangent Arcus Tangens radians to degrees Bogenmaß nach Grad degrees to radians Grad nach Bogenmaß pi constant PI natural log constant Eulersche Zahl Define Math Field Equation Mathematischen Ausdruck definieren Field References Feldverweis Reference &Level Verweis &Stufe Reference &Type Verweis &Typ Available &Field List Verfügbare &Feldliste &Result Type &Ergebnistyp Description Beschreibung &Equation &Gleichung Equation error: {} Fehler in Gleichung: {} Boolean Result Bool'sches Ergebnis Text Result Text Ergebnis Arithmetic Operators Arithmetische Operatoren Comparison Operators Vergleichsoperatoren Text Operators Text Operatoren equal to Ist gleich less than Ist kleiner greater than Ist größer less than or equal to Ist kleiner oder gleich greater than or equal to Ist größer oder gleich not equal to Ist nicht gleich true value, condition, false value Wahrer Wert, Bedingung, Falscher Wert true if 1st text arg starts with 2nd arg Wahr, wenn 1. Argument mit 2. Argument beginnt true if 1st text arg ends with 2nd arg Wahr, wenn 1. Argument mit 2. Argument endet true if 1st text arg contains 2nd arg Wahr, wenn 1.Argument 2.Argument enthält concatenate text Text aneinanderhängen join text using 1st arg as separator Text verbinden mit 1. Argument als Trenner convert text to upper case Text in Großbuchstaben konvertieren convert text to lower case Text in Kleinbuchsrtaben konvertieren in 1st arg, replace 2nd arg with 3rd arg Ersetze in 1. Argument das 2. Argument durch das 3. Argument Operations Operationen O&perator Type Typ des O&perators Oper&ator List Liste der Oper&atoren logical and Logisches Und logical or Logisches Oder Output HTML HTML Ausgabe Evaluate &HTML tags Bewerte HTML Tags Child Type Limits Kind Typ Grenzen [All Types Available] [Alle Typen verfügbar] &Select All &Alles auswählen Select &None Nichts auswählen Number Result Anzahl Ergebnis Count Zählen Number of Children Anzahl der Kinder dataeditors Today's &Date Heutiges &Datum &Open Link &Verweis öffnen Open &Folder &Verzeichnis öffnen External Link Externer Verweis Scheme Schema &Browse for File Datei &suchen File Path Type Verzeichnis Angabe Absolute Absolut Relative Relativ Address Adresse Display Name Anzeigename &OK &OK &Cancel &Abbrechen TreeLine - External Link File Verweis zu externer TreeLine Datei &Go to Target &Gehe zu Ziel Internal Link Interner Verweis &Open Picture &Öffne Bild Picture Link Verweis auf Bild TreeLine - Picture File TreeLine Bilddatei Set to &Now Auf &heute setzen Clear &Link Verweis löschen (Click link target in tree) Klicke Verweis Ziel im Baum link Verweis dataeditview exports Bookmarks Lesezeichen TreeLine - Export HTML TreeLine - Exportiere HTML TreeLine - Export Text Titles TreeLine - Exportiere Textüberschriften TreeLine - Export Plain Text TreeLine - Exportiere Text TreeLine - Export Text Tables TreeLine - Exportiere Text Tabelle TreeLine - Export Generic XML TreeLine - Exportiere Generisches XML TreeLine - Export TreeLine Subtree TreeLine - Exportiere TreeLine Teilbaum TreeLine - Export ODF Text TreeLine - Exportiere ODF Text TreeLine - Export HTML Bookmarks TreeLine - Exportiere HTML Lesezeichen TreeLine - Export XBEL Bookmarks TreeLine - Exportiere XBEL Lesezeichen &HTML &HTML &Text &Text &ODF Outline &ODF Struktur Book&marks &Lesezeichen &Single HTML page &Einzelne HTML Seite Single &HTML page with navigation pane Einzelne &HTML Seite mit Navigationsleiste Multiple HTML &pages with navigation pane Mehrere HTML &Seiten mit Navigationsleiste Multiple HTML &data tables Mehrere HTML &Datentabellen &Tabbed title text &Titelzeile mit Tabulator &Unformatted output of all text &Unformatierte Ausgabe des gesamten Textes &HTML format bookmarks &HTML formatierte Lesezeichen &XBEL format bookmarks &XBEL formatierte Lesezeichen File Export Datei Export Choose export format type Ausgabeformat wählen Choose export format subtype Ausgabe Unterformat wählen Choose export options Ausgabeoptionen wählen What to Export Was wird exportiert &Entire tree &Gesamter Baum Selected &branches &Ausgewählte Teilbäume Selected &nodes Ausgewählte &Knoten Other Options Andere Optionen &Only open node children &Nur geöffnete Kindknoten Include &print header && footer &Kopf- und Fußzeile einschließen &Columns &Spalten Navigation pane &levels &Stufen der Navigationsleiste Error - export template files not found. Check your TreeLine installation. Fehler - Export Vorlage nicht gefunden. Überprüfe deine TreeLine Installation. Error - cannot link to unsaved TreeLine file. Save the file and retry. Fehler - Kann nicht auf nicht gespeicherte TreeLine Datei verweisen. Speichere die Datei und versuche es erneut. Warning - no relative path from "{0}" to "{1}". Continue with absolute path? Warnung - kein relativer Pfad von "{0}" nach "{1}". Weitermachen mit absolutem Pfad? Parent Eltern Tree&Line Tree&Line &XML (generic) &XML (generisch) Live tree view, linked to TreeLine file (for web server) Live Baum Ansicht, verlinkt mit der TreeLine Datei (für Web Server) Live tree view, single file (embedded data) Live Baum Ansicht, eine Datei (Daten eingeschlossen) &Comma delimited (CSV) table of descendants (level numbers) &Komma-getrennte Tabelle (CSV) der Nachkommen (Nummern Grad) Comma &delimited (CSV) table of children (single level) Komma-&getrennte Tabelle (CSV) der Kinder (einzelner Grad) Tab &delimited table of children (&single level) Tab-&getrennte Tabelle der Kinder (&einzelner Grad) &Old TreeLine (2.0.x) Altes TreeLine Format (2.0.x) &TreeLine Subtree TreeLine Teilbaum &Include root nodes einschließlich Wurzel Knoten Must select nodes prior to export Sie müssen Knoten vor dem Export auswählen. fieldformat yes/no ja/nein true/false wahr/falsch T/F W/F Y/N J/N Text Text HtmlText HtmlText OneLineText Einzeiler SpacedText Text, Leerzeichen getrennt Number Nummer Math Mathematisch Numbering Nummer Boolean Boolean Date Datum Time Zeit Choice Auswahlfeld AutoChoice Auto Auswahlfeld Combination Kombinationsfeld AutoCombination Auto-Kombinationsfeld ExternalLink Externer Verweis InternalLink Interner Verweis Picture Bild RegularExpression Regulärer Ausdruck Now Heute Optional Digit # Optionale Ziffer # Required Digit 0 Erforderliche Ziffer 0 Digit or Space (external) <space> Ziffer oder Leertaste (Extern) <space> Decimal Point . Dezimalpunkt . Decimal Comma , Dezimalkomma , Space Separator (internal) <space> Leertaste Trenner (Intern) <space> Optional Sign - Optionales Vorzeichen - Required Sign + Erforderliches Vorzeichen + Exponent (capital) E Exponent (Groß) E Exponent (small) e Exponent (Klein) e Number 1 Ziffer 1 Capital Letter A Großbuchstabe A Small Letter a Kleinbuchstabe a Capital Roman Numeral I Große römische Ziffer I Small Roman Numeral i Kleine römische Ziffer i Level Separator / Stufentrenner / Section Separator . Sektionstrenner . "/" Character // "/" Zeichen // "." Character .. "." Zeichen .. Outline Example I../A../1../a)/i) Gliederungsbeispiel I../A../1../a)/i) Section Example 1.1.1.1 Überschrift Beispiel 1.1.1.1 Separator / Trenner / Example 1/2/3/4 Beispiel 1/2/3/4 Any Character . Beliebiges Zeichen . End of Text $ Texteende $ 0 Or More Repetitions * 0 oder mehr Wiederholungen * 1 Or More Repetitions + 1 oder mehr Wiederholungen + 0 Or 1 Repetitions ? 0 oder 1 Wiederholung ? Set of Numbers [0-9] Menge von Ziffern [0-9] Lower Case Letters [a-z] Kleinbuchstabe [a-z] Upper Case Letters [A-Z] Großbuchstabe [A-Z] Not a Number [^0-9] Keine Ziffer [^0-9] Or | Oder | Escape a Special Character \ Escape für Sonderzeichen \ DateTime Datum/Zeit Day (1 or 2 digits) %-d Tag (1 oder 2 Ziffern) Day (2 digits) %d Tag (2 Ziffern) Weekday Abbreviation %a Wochentag Abkürzung Weekday Name %A Wochentag Name Month (1 or 2 digits) %-m Monat (1 oder 2 Ziffern) Month (2 digits) %m Monat (2 Ziffern) Month Abbreviation %b Monat Abkürzung Month Name %B Monat Name Year (2 digits) %y Jahr (2 Ziffern) Year (4 digits) %Y Jahr (4 Ziffern) Week Number (0 to 53) %-U Wochennummer (0 bis 53) Day of year (1 to 366) %-j Tag des Jahres (1 bis 366) Hour (0-23, 1 or 2 digits) %-H Stunde (0-23, 1 oder 2 Ziffern) Hour (00-23, 2 digits) %H Stunde (00-23, 2 Ziffern) Hour (1-12, 1 or 2 digits) %-I Stunde (1-12, 1 oder 2 Ziffern) Hour (01-12, 2 digits) %I Stunde (01-12, 2 Ziffern) Minute (1 or 2 digits) %-M Minute (1 oder 2 Ziffern) Minute (2 digits) %M Minute (2 Ziffern) Second (1 or 2 digits) %-S Sekunde (1 oder 2 Ziffern) Second (2 digits) %S Sekunde (2 Ziffern) Microseconds (6 digits) %f Microsekunde (6 Ziffern) AM/PM %p AM/PM Comma Separator \, Komma Trenner \, Dot Separator \. Punkt Trenner \. DescendantCount Anzahl der Nachkommen genboolean true wahr false falsch yes ja no nein globalref TreeLine Files TreeLine Dateien TreeLine Files - Compressed TreeLine Dateien (komprimiert) TreeLine Files - Encrypted TreeLine Dateien (verschlüsselt) All Files Alle Dateien HTML Files HTML Dateien Text Files Text Dateien XML Files XML Dateien ODF Text Files ODF Dateien Treepad Files Treepad Dateien PDF Files PDF Dateien CSV (Comma Delimited) Files CSV Datei (Komma-getrennt) All TreeLine Files Alle Treeline Dateien Old TreeLine Files Alte Treeline Dateien helpview &Back &Zurück &Forward &Vorwärts &Home &Eigenes Verzeichnis Find: Suchen: Find &Previous &Rückwärts Suchen Find &Next &Vorwärts Suchen Text string not found Text nicht gefunden Tools Werkzeuge imports &Tab indented text, one node per line &Mit Tabulator eingerückter Text, Knoten je Zeile Tab delimited text table with header &row Tabulator getrennter Text mit Kopfzeile Plain text &paragraphs (blank line delimited) Text &Blöcke (Beendet mit Leerzeile) Treepad &file (text nodes only) Treepad &Datei (nur Text) &Generic XML (non-TreeLine file) Generisches &XML (Keine TreeLine Datei) Open &Document (ODF) outline Open &Document (ODF) Gliederung &HTML bookmarks (Mozilla Format) &HTML Lesezeichen (Mozilla Format) &XML bookmarks (XBEL format) &XML Lesezeichendatei (XBEL-Format) FOLDER VERZEICHNIS BOOKMARK LESEZEICHEN SEPARATOR TRENNER Link Verweis Text Text Import File Import Datei Choose Import Method Import Methode auswählen Invalid File Ungültige Datei "{0}" is not a valid TreeLine file. Use an import filter? "{0}" ist keine TreeLine Datei. Importfilter verwenden? TreeLine - Import File TreeLine - Import Datei Error - could not read file {0} Fehler - Kann Datei {0} nicht lesen Error - improper format in {0} Fehler - ungültiges Format in {0} TABLE TABELLE Bookmarks Lesezeichen Too many entries on Line {0} Zu viele Einträge in der Zeile {0} Plain text, one &node per line (CR delimited) Nur Text, ein &Knoten pro Zeile (CR getrennt) Bad CSV format on Line {0} Fehler im CSV Format bei Zeile {0} Co&mma delimited (CSV) text table with level column && header row Ko&mma-getrennter (CSV) Text Tabelle mit Stufe Spalte && Kopfzeile Reihe Comma delimited (CSV) text table &with header row Ko&mma-getrennter (CSV) Text Tabelle mit Kopfzeile Other Andere Old Tree&Line File (1.x or 2.x) Alte Tree&Line Datei (1.x oder 2.x) Invalid level number on line {0} Falsche Ebene Nummer on line {0} Invalid level structure Fehlerhafte Ebenen Struktur No headings found matheval Illegal "{}" characters Ungültige Zeichen "{}" Child references must be combined in a function Verweise auf Kinder müssen in einer Funktion kombiniert werden Illegal syntax in equation Ungültige Syntax in Ausdruck Illegal function present: {0} Ungültige Funktion: {0} Illegal object type or operator: {0} Ungültiger Objekttyp oder Operator: {0} Invalid field modifiers miscdialogs &OK &OK &Cancel &Abbrechen Fields Felder File Properties Datei Eigenschaften File Storage Datei Speicherung &Use file compression Datei&komprimierung verwenden Use file &encryption Datei&verschlüsselung verwenden Spell Check Rechtschreibprüfung Language code or dictionary (optional) Sprachcode oder Wörterbuch (optional) Math Fields Mathematisches Feld &Treat blank fields as zeros &Leere Felder als Null behandeln Encrypted File Password Passwort der verschlüsselten Datei Type Password for "{0}": Passwort für {0} eingeben: Type Password: Passwort eingeben: Re-Type Password: Passwort wiederholen: Remember password during this session Passwort für diese Sitzung merken Zero-length passwords are not permitted Leere Passwörter sind nicht erlaubt Re-typed password did not match Passworte stimmen nicht überein Default - Single Line Text Standard - Einzeiliger Text &Search Text &Suchtext What to Search Nach was wird gesucht Full &data Gesamte &Daten &Titles only Nur &Titel How to Search Wie wird gesucht &Key words &Schlüsselworte Key full &words &Ganze Worte F&ull phrase Ganzer &Satz &Regular expression &Regulärer Ausdruck Find Suchen Find &Previous Suche &Vorherige Find &Next Suche &Nächster Filter Filter &Filter &Filter &End Filter Filter &Ende &Close &Schließen Error - invalid regular expression Fehler - Ungültiger regulärer Ausdruck Search string "{0}" not found Suchtext "{0}" nicht gefunden Find and Replace Suchen und Ersetzen Replacement &Text Ersetzungs&text Any &match Jedes &Vorkommen Full &words Ganze &Worte Re&gular expression Regulärer &Ausdruck &Node Type &Knotentyp N&ode Fields &Felder &Find Next Suche &Nächster &Replace &Ersetzen Replace &All &Alle Ersetzen [All Types] [Alle Typen] [All Fields] [Alle Felder] Search text "{0}" not found Suchtext "{0}" nicht gefunden Error - replacement failed Fehler - Ersetzung nicht möglich Replaced {0} matches {0} Stellen ersetzt Sort Nodes Konten sortieren What to Sort Was wird sortiert &Entire tree &Gesamter Baum Selected &branches Ausgewählte &Teilbäume Selection's childre&n &Kinder der ausgewählten Teilbäume Selection's &siblings &Geschwister der ausgewählten Telibäume Sort Method Sortiermethode &Predefined Key Fields &Vordefinierte Schlüsselfelder Node &Titles Knoten&titel Sort Direction Sortierrichtung &Forward &Vorwärts &Reverse &Rückwärts &Apply &Anwenden Update Node Numbering Nummerierung erneuern What to Update Was soll erneuert werden &Selection's children &Kinder der Auswahl Root Node Wurzelelement Include top-level nodes Knoten der ersten Ebene einschliessen Handling Nodes without Numbering Fields Behandlung von Knoten ohne Nummerierungsfelder &Ignore and skip &Ignorieren &Restart numbers for next siblings &Nummerierung für nächste Geschwister neu starten Reserve &numbers Nummerierung &umkehren TreeLine Numbering TreeLine Nummerierung No numbering fields were found in data types Keine Nummerierungsfelder gefunden File Menu Datei Menü File Datei Edit Menu Bearbeiten Menü Edit Bearbeiten Node Menu Knoten Menü Node Knoten Data Menu Daten Menü Data Daten Tools Menu Werkzeug Menü Tools Werkzeug View Menu Ansicht Menü View Ansicht Window Menu Fenster Menü Window Fenster Help Menu Hilfe Menü Help Hilfe Keyboard Shortcuts Tastaturkürzel &Restore Defaults &Standard wiederherstellen Key {0} is already used Taste {0} bereits belegt Clear &Key Lösche &Taste --Separator-- --Trenner-- Customize Toolbars Symbolleisten konfigurieren Toolbar &Size Symbolleisten&größe Small Icons Kleine Icons Large Icons Große Icons Toolbar Quantity Anzahl Symbolleisten &Toolbars &Symbolleisten A&vailable Commands &Verfügbare Funktionen Tool&bar Commands &Symbolleisten Funktionen Move &Up Nach &oben verschieben Move &Down Nach &unten verschieben Tree View Font Schriftart für Baumanzeige Output View Font Schriftart für Ausgabe Editor View Font Schriftart für Editor No menu Kein Menü TreeLine - Serious Error TreeLine - Schwerer Fehler A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. Ein schwerer Fehler ist aufgetreten. TreeLine kann sich in einem instabilen Zustand befinden. Empfehlung, die Datei unter einem anderen Namen zu speichern und TreeLine neu zu starten. Das Debug Info unterhalb kann kopiert werden und per Mail an doug101@bellz.org geschickt werden zusammen mit Erläuterungen, unter welchen Umständen, der Fehler auftrat. Format Menu Format Menü Format Format Customize Fonts Schriftarten Anpassen &Use system default font &System Schriftart verwenden App Default Font Standardschriftart &Use app default font &Standard Schriftart verwenden Externally Modified File &Overwrite File &Cancel Save File was externally modified at {} nodeformat Name Name optiondefaults Monday Montag Tuesday Dienstag Wednesday Mittwoch Thursday Donnerstag Friday Freitag Saturday Samstag Sunday Sonntag Startup Condition Programmstart Automatically open last file used Die zuletzt benutzte Datei automatisch öffnen Show descendants in output view Unterknoten in der Ansicht anzeigen Restore tree view states of recent files Baumansicht von kürzlich geöffneten Dateien wierherstellen Restore previous window geometry Fenstereinteilung wiederherstellen Features Available Verfügbare Funktionen Open files in new windows Öffne Dateien in neuem Fenster Click node to rename Klick auf Knoten zum Umbenennen Rename new nodes when created Neue Knoten nach dem Anlegen umbenennen Tree drag && drop available Verschieben von Bäumen mit der Maus erlauben Show icons in the tree view Icons in der Baumansicht anzeigen Show math fields in the Data Edit view Mathematische Felder im Bearbeiten Fenster anzeigen Show numbering fields in the Data Edit view Nummerierungsfelder im Bearbeiten Fenster anzeigen Undo Memory Speicher für Wiederherstellungen Number of undo levels Anzahl der möglichen Wiederherstellungen Auto Save Automatisches Speichern Minutes between saves (set to 0 to disable) Minuten zwischen Speichervorgängen (0 für Abschalten) Recent Files Zuletzt geöffnete Dateien Number of recent files in the file menu Anzahl zuletzt geöffneter Dateien Data Editor Formats Formate im Bearbeitungsfenster Times Zeitdarstellung Dates Datumsdarstellung First day of week Erster Wochentag Appearance Aussehen Child indent offset (in font height units) Einrückung für Kinder (In Schriftart Einheiten) Show breadcrumb ancestor view Zeige Breadcrumb Vorfahren Ansicht Show child pane in right hand views Zeige Kind Ausschnitt in der rechten Ansicht Remove inaccessible recent file entries Lösche alle nicht vorhandenen aktuellen Datei-Einträge Activate data editors on mouse hover Aktiviere den Daten Editor bei schwebender Maus Minimize application to system tray Minimiere Programm in die Systemleiste Indent (pretty print) TreeLine JSON files Druckoptimierte TreeLine JSON Dateien mit Einrückung Limit data editor height to window size Begrenzung der Höhe des Dateneditors auf die Fenstergröße options Choose configuration file location Ablage Konfigurationsfile User's home directory (recommended) Benutzerverzeichnis (empfohlen) Program directory (for portable use) Programmverzeichnis (für portablen Einsatz) &OK &OK &Cancel &Abbrechen printdata Error initializing printer Fehler beim Initialisieren des Druckers TreeLine - Export PDF TreeLine - PDF Exportieren Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Warnung: Seitengröße und Randeinstellung werden vom derzeitigen Drucker nicht unterstützt. Sollen die Einstellungen berichtigt werden? Warning: Page size setting unsupported on current printer. Save adjustment? Warnung: Seitengröße werden vom derzeitigen Drucker nicht unterstützt. Sollen die Einstellungen berichtigt werden? Warning: Margin settings unsupported on current printer. Save adjustments? Warnung: Randeinstellung werden vom derzeitigen Drucker nicht unterstützt. Sollen die Einstellungen berichtigt werden? printdialogs Print Preview Druckvorschau &Print... &Drucken... &General Options Allgemeine &Einstellungen &Font Selection Schrift&auswahl &Header/Footer &Kopf-/Fußzeile Print Pre&view... Druck&vorschau... &OK &OK &Cancel &Abbrechen What to print Was wird gedruckt &Entire tree Gesamter Baum Selected &branches Ausgewählte Teilbäume Selected &nodes Ausgewählte Knoten Features Eigenschaften &Include root node Wurzelelement hinzunehmen &Keep first child with parent Das erste Unterelement mit dem Elternelement zusammen anzeigen Letter (8.5 x 11 in.) Letter (8.5 × 11 Inch) Legal (8.5 x 14 in.) Legal (8.5 × 14 Inch) Tabloid (11 x 17 in.) Tabloid (11 × 17 Inch) A3 (279 x 420 mm) A3 (279 × 420 mm) A4 (210 x 297 mm) A4 (210 × 297 mm) A5 (148 x 210 mm) A5 (148 × 210 mm) Paper &Size Papiergröße Orientation Orientierung &Units &Einheiten Columns Spalten &Number of columns Spaltenanzahl Default Font standard Schriftart Select Font Schriftart auswählen &Font &Schriftart Font st&yle Schrifts&til Sample Beispiel &Header Left Kopfzeile &Links Header C&enter Kopfzeile Mitt&e Footer &Left &Fußzeile Links Footer Ce&nter Fußzeile M&itte Fiel&ds Felder Header and Footer Kopf- und Fußzeile Extra Text Extratext &Prefix Präfi&x Format &Help &Hilfe zu den Formaten Fit Width Breite anpassen Fit Page Seite anpassen Zoom In Vergrößern Zoom Out Verkleinern Previous Page Vorherige Seite Next Page Nächste Seite Single Page Einzelne Seite Facing Pages Gegenüberliegende Seiten Print Setup Druckeinstellungen Print Drucken Printing Setup Druckeinstellungen Page &Setup Seiteneinstellungen Included Nodes Berücksichtigte Knoten Onl&y open node children Nur Kinder von geöffneten Knoten &Draw lines to children Linien zu den Kindern zeichnen Indent Einrücken Indent Offse&t (line height units) Abstand beim Einrücken (Einheit Zeilenhöhe) Custom Size Benutzerdefinierte Größe Inches (in) Inch (in) Millimeters (mm) Millimeter (mm) Centimeters (cm) Zentimeter (cm) &Width: &Breite: Height: &Höhe: Portra&it &Hochformat Lan&dscape &Querformat Margins Ränder &Left: &Links: &Top: &Oben: &Right: &Rechts: &Bottom: &Unten: He&ader: &Kopfzeile: Foot&er: &Fußzeile: Space between colu&mns Abstand zwischen &Spalten &Use TreeLine output view font &TreeLine Ausgabe Schriftart verwenden Si&ze &Größe AaBbCcDdEeFfGg...TtUuVvWvXxYyZz AaBbCcDcEeFfGg...TtUuVvWwXxYyZz Header &Right Kopfzeile &Rechts Footer Righ&t Fusszeile &Rechts Field For&mat Feldf&ormat Field Format for "{0}" Feldformat für "{0}" Output &Format Ausgabeformat &Suffix &Suffix Error: Page size or margins are invalid Fehler: Seitengröße oder Seitenränder sind ungültig TreeLine PDF Printer TreeLine PDF Drucker Select &Printer Wähle &Drucker recentfiles spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? Kann weder aspell.exe, ispell.exe oder hunspell.exe finden. Speicherort suchen? Spell Check Error Fehler in der Rechtschreibprüfung Locate aspell.exe, ipsell.exe or hunspell.exe Suche aspell.exe, ispell.exe oder hunspell.exe Program (*.exe) Programm (*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed Fehler bei der Rechtschreibprüfung. Stellen Sie sicher, dass aspell, ispell oder hunspell installiert ist TreeLine Spell Check TreeLine Rechtschreibprüfung Finished spell checking Rechtschreibprüfung beendet Spell Check Rechtschreibprüfung Not in Dictionary Nicht im Wörterbuch Word: Wort: Context: Kontext: Suggestions Vorschläge Ignor&e &Ignorieren &Ignore All &Alles Ignorieren &Add &Hinzufügen Add &Lowercase Hinzufügen in &Kleinbuchstaben &Replace &Ersetzen Re&place All Alles E&rsetzen &Cancel &Abbrechen Finished checking the branch Continue from the top? Rechtschreibprüfung für den Zweig beendet. Wieder von oben anfangen? titlelistview Select in Tree Auswahl im Baum treeformats DEFAULT STANDARD FILE DATEI TYPE TYP FIELD FELD FieldType FELDTYP TitleFormat Titelformat OutputFormat Ausgabeformat SpaceBetween Zwischenraum FormatHtml HTML-Format Bullets Kugeln Table Tabelle ChildType KinderTyp Icon Icon">Icon GenericType GenerischerTyp ConditionalRule Bedingungen ListSeparator ListenTrennzeichen ChildTypeLimit unfinished Format Format">Format Prefix Prefix Suffix Suffix InitialValue Anfangswert NumLines Zeilennummerierung SortKeyNum Sortierschlüssel SortForward AufwärtsSortierten EvalHtml unfinished treelocalcontrol Error - could not delete backup file {} Fehler: Kann Sicherheitskopie {0} nicht löschen Save changes to {}? Änderungen an {0} abspeichern? Save changes? Änderungen abspeichern? &Save S&peichern Save File Datei speichern Save the current file Aktuelle Datei speichern Save &As... Speichern &unter... Save the file with a new name Die Datei unter einem neuen Namen speichern &Export... &Exportieren... Export the file in various other formats Die Datei in unterschiedlichen Formaten exportieren Prop&erties... &Eigenschaften... Set file parameters like compression and encryption Datei Eigenschaften wie Komprimierung oder Verschlüsselung setzen P&rint Setup... &Drucken einrichten... Set margins, page size and other printing options Ränder, Seitengröße und andere Druckeinstellungen Print Pre&view... Druck&vorschau... Show a preview of printing results Vorschau der Druckergebnisse anzeigen &Print... &Drucken... Print tree output based on current options Baum basierend auf aktuellen Einstellungen drucken Print &to PDF... Nach &PDF drucken... Export to PDF with current printing options Nach PDF mit aktuellen Druckoptionen exportieren &Undo &Rückgängig Undo the previous action Die letzte Aktion rückgängig machen &Redo W&iederherstellen Redo the previous undo Die letzte Aktion wiederherstellen Cu&t &Ausschneiden Cut the branch or text to the clipboard Den Teilbaum oder Text ausschneiden und in die Zwischenablage legen &Copy &Kopieren Copy the branch or text to the clipboard Den Teilbaum oder den Text in die Zwischenablage kopieren &Paste Ein&fügen Paste nodes or text from the clipboard Knoten oder Text von der Zwischenablage einfügen Paste non-formatted text from the clipboard Unformatierten Text von der Zwischenablage einfügen &Bold Font &Fettschrift Set the current or selected font to bold Die aktuelle oder ausgewählte Schriftart auf "fett" setzen &Italic Font &Kursivschrift Set the current or selected font to italic Die aktuelle oder ausgewählte Schriftart auf "kursiv" setzen U&nderline Font &Unterstreichen Set the current or selected font to underline Die aktuelle oder ausgewählte Schriftart auf "unterstreichen" setzen &Font Size &Schriftart Größe Set size of the current or selected text Die Größe der aktuellen oder selektierten Schriftart setzen Small Klein Default Standard Large Groß Larger Größer Largest Am Größten Set Font Size Schriftart Größe setzen Font C&olor... Schriftart &Farbe... Set the color of the current or selected text Die Farbe der aktuellen oder ausgewählten Schriftart setzen &External Link... &Externer Verweis... Add or modify an extrnal web link Einen externen Verweis hinzufügen oder ändern Internal &Link... &Interner Verweis... Add or modify an internal node link Internen Verweis ändern oder hinzufügen Clear For&matting &Formatierung entfernen Clear current or selected text formatting Die Formatierung am aktuellen oder selektierten Text entfernen &Rename &Umbenennen Rename the current tree entry title Den Titel des aktuellen Knotens ändern Insert Sibling &Before &Vor ausgewähltem Element einfügen Insert new sibling before selection Ein neues Element vor dem ausgewählten Element einfügen Insert Sibling &After &Nach ausgewähltem Element einfügen Insert new sibling after selection Ein neues Element nach dem ausgewählten Element einfügen Add &Child &Kind hinzufügen Add new child to selected parent Neues Kind zu aktuellem Knoten hinzufügen &Delete Node Knoten &löschen Delete the selected nodes Die ausgewählten Knoten löschen &Indent Node Knoten &einrücken Indent the selected nodes Die ausgewählten Knoten einrücken &Unindent Node Knoten &ausrücken Unindent the selected nodes Die ausgewählten Knoten "ausrücken" (um eine Ebene nach links verschieben) &Move Up Nach &oben verschieben Move the selected nodes up Die ausgewählten Knoten nach oben verschieben M&ove Down Nach &unten verschieben Move the selected nodes down Die ausgewählten Knoten nach unten verschieben Move &First Zum Anfang verschieben Move the selected nodes to be the first children Das ausgewählte Knoten als erstes Unterelement setzen Move &Last Zum Ende verschieben Move the selected nodes to be the last children Das ausgewählte Knoten als letztes Unterelement setzen &Set Node Type Knoten&typ zuweisen Set the node type for selected nodes Den Typ für den ausgewählten Knoten setzen Set Node Type Knotentyp zuweisen Copy Types from &File... Typen aus &Datei kopieren... Copy the configuration from another TreeLine file Konfiguration aus einer anderen TreeLine-Datei übernehmen Flatten &by Category &Abflachen nach Kategorie Collapse descendants by merging fields Kinder zusammenfassen und Felder vereinen Add Category &Level... Kategorie &Hierarchieebene einfügen... Insert category nodes above children Kategorieebene oberhalb der Unterknoten einfügen &Spell Check... &Rechtschreibprüfung... &New Window &Neues Fenster Open a new window for the same file Neues Fenster für die gleiche Datei öffnen Error - could not write to {} Fehler - konnte nicht nach {0} schreiben TreeLine - Save As TreeLine - Speichern unter Error - could not write to file Fehler - konnte nicht auf Datei schreiben TreeLine - Open Configuration File TreeLine - Konfigurationsdatei schreiben Error - could not read file {0} Fehler - Konnte Datei {0} nicht lesen Cannot expand without common fields Ohne gemeinsame Felder kann der Baum nicht expandiert werden Category Fields Kategoriefelder Select fields for new level Felder für die neue Ebene auswählen File saved Datei gespeichert Pa&ste Plain Text Nu&r Text einfügen Paste C&hild Kind Knoten einfügen Paste a child node from the clipboard Kind Knoten von der Zwischenablage einfügen Paste Sibling &Before Füge Geschwister Knoten &davor Paste a sibling before selection Füge Geschwister Knoten vor Auswahl ein Paste Sibling &After Füge Geschwister Knoten d&ahinter Paste a sibling after selection Füge Geschwister Knoten hinter Auswahl ein Paste Cl&oned Child Füge geklonten Kind Knoten ein Paste a child clone from the clipboard Füge geklonten Kind Knoten von der Zwischenablage ein Paste Clo&ned Sibling Before Füge geklo&nten Geschwwister Knoten davor ein Paste a sibling clone before selection Füge Geschwister Knoten Klon vor der Auswahl ein Paste Clone&d Sibling After Füge geklonten Geschwister Knoten &danach ein Paste a sibling clone after selection Füge Geschwister Knoten Klon nach der Auswahl ein Clone All &Matched Nodes Klone alle &passenden Knoten Convert all matching nodes into clones Konvertiere alle passenden Knoten in Klone &Detach Clones Trenne Klone Detach all cloned nodes in current branches Trenne alle Klone Knoten im aktuellen Zweig S&wap Category Levels Tausche Kategorie Ebene Swap child and grandchild category nodes Tausche Kind und Enkel Kategorie Knoten Converted {0} branches into clones {0} Zweige in Klone konvertiert No identical nodes found Keine identischen Knoten gefunden Warning - file corruption! Skipped bad child references in the following nodes: Warnung - Datei Fehler! Überspringe fehlerhafte Kind Verweise in den folgenden Knoten: Spell check the tree's text data Rechtschreibprüfung für Text &Regenerate References Erstelle Verweise neu Force update of all conditional types & math fields Erzwinge Aktualisierung alle konditonalen Bedingungen & Mathematischen Feldern Insert &Date &Datum einfügen Insert current date as text Aktuelles Datum als Text einfügen St&rikethrough Font Set the current or selected font to strikethough treemaincontrol Warning: Could not create local socket Warnung - Socket kann nicht geöffnet werden Error - could not write config file to {} Fehler - Kann Konfigurationsdatei nicht auf {} schreiben Error - could not read file {0} Fehler - Kann Datei {0} nicht lesen Backup file "{}" exists. A previous session may have crashed Sicherheitskopie {} existiert. Eine vorherige Sitzung ist möglicherweise abgestürzt &Restore Backup Sicherungskopie &wiederherstellen &Delete Backup Sicherungskopie &löschen &Cancel File Open Datei öffnen &abbrechen Error - could not rename "{0}" to "{1}" Fehler - Kann {0} nicht nach {1} umbenennen Error - could not remove backup file {} Fehler - Kann Sicherheitskopie {} nicht entfernen &New... &Neu... New File Neue Datei Start a new file Eine neue Datei öffnen &Open... &Öffnen... Open File Datei öffnen Open a file from disk Datei von Datenträger öffnen Open Sa&mple... &Beispiele... Open Sample Beispiel öffnen Open a sample file Eine Beispieldatei öffnen &Import... &Importieren... Open a non-TreeLine file Eine nicht TreeLine Datei laden &Quit &Beenden Exit the application Die Anwendung beenden &Select All &Alles auswählen Select all text in an editor Gesamten Text im Editor auswählen &Configure Data Types... &Datentypen konfigurieren... Modify data types, fields & output lines Konfiguriere Datentypen, Felder und Ausgabezeilen Sor&t Nodes... Knoten&sortierung... Define node sort operations Knotensortierung definieren Update &Numbering... &Nummerierung anpassen... Update node numbering fields Die Nummerierung anpassen &Find Text... &Suche Text... Find text in node titles & data Text in Knoten suchen &Conditional Find... &Bedingtes Suchen... Use field conditions to find nodes Feldbasierte Bedingungen verwenden um Knoten zu finden Find and &Replace... Suchen und &Ersetzen... Replace text strings in node data Text in Knoten ersetzen &Text Filter... &Textfilter... Filter nodes to only show text matches Knoten filtern auf übereinstimmenden Text C&onditional Filter... &Bedingter Filter... Use field conditions to filter nodes Feldbasierte Bedingungen verwenden &General Options... Allgemeine &Einstellungen... Set user preferences for all files Benutzereinstellungen für alle Dateien Set &Keyboard Shortcuts... &Tastaturkürzel konfigurieren... Customize keyboard commands Tastaturkürzel anpassen C&ustomize Toolbars... &Symbolleiste anpassen... Customize toolbar buttons Symbolleiste Aktionen anpassen Customize Fo&nts... &Schriftarten anpassen... Customize fonts in various views Schriftarten der Ansichten anpassen &Basic Usage... &Grundlegende Verwendung... Display basic usage instructions Grundlegende Anleitungen anzeigen &Full Documentation... &Umfassende Dokumentation... Open a TreeLine file with full documentation TreeLine Datei mit umfassender Dokumentation anzeigen &About TreeLine... Über &TreeLine... Display version info about this program Versionsinformationen zum Programm anzeigen &Select Template &Vorlagenauswahl TreeLine - Open File TreeLine - Datei Öffnen Open Sample File Beispieldatei öffnen &Select Sample &Beispiel auswählen Conditional Find Bedingtes suchen Conditional Filter Bedingter Filter General Options Allgemeine Einstellungen Error - basic help file not found Fehler - Grundlegende Hilfedatei nicht gefunden TreeLine Basic Usage TreeLine grundlegende Verwendung Error - documentation file not found Fehler - Dokumentation nicht gefunden Error - invalid TreeLine file {0} Fehler - ungültige TreeLine Datei {0} TreeLine version {0} TreeLine Version {0} written by {0} geschrieben von {0} Library versions: Bibliothek Versionen: missing directory fehlendes Verzeichnis Show C&onfiguration Structure... Zeige Struktur der Konfiguration Show read-only visualization of type structure Zeige nur-lesende Visualisierung der Typ Struktur Custo&mize Colors... Farben anpassen Customize GUI colors and themes GUI Farben und Thema anpassen treemodel treenode New Neu treeopener treestructure Main Hauptprogramm treeview Filtering by "{0}", found {1} nodes Filtern nach {0}, {1} Knoten gefunden Conditional filtering, found {0} nodes Bedingtes Filter hat {0} Knoten gefunden Search for: Suche nach: Search for: {0} Suche nach: {0} Search for: {0} (not found) Suche nach: {0} (nicht gefunden) Next: {0} Nächste: {0} Next: {0} (not found) Nächste: {0} (nicht gefunden) treewindow Data Output Datenansicht Data Edit Datenbearbeitung Title List Überschriftsliste &Expand Full Branch Teilbaum vollständig &expandieren Expand all children of the selected nodes Alle Kinder der selektierten Knoten expandieren &Collapse Full Branch Teilbaum vollständig &einklappen Collapse all children of the selected nodes Alle Kinder der selektierten Knoten einklappen &Previous Selection &Vorherige Auswahl Return to the previous tree selection Zu der vorherigen Selektion zurückkehren &Next Selection &Nachfolgende Auswahl Go to the next tree selection in history Die folgende Selektion wieder aktivieren Show Data &Output &Ansicht anzeigen Show data output in right view Die Daten-Ansicht in der rechten Fensterhälfte anzeigen Show Data &Editor Edit&or anzeigen Show data editor in right view Den Editor in der rechten Fensterhälfte anzeigen Show &Title List &Überschriftsliste anzeigen Show title list in right view Die Überschriften-Liste in der rechten Fensterhälfte anzeigen &Show Child Pane &Kinder mit anzeigen Toggle showing right-hand child views Die Kinder in der Ausgabeansicht mit anzeigen Toggle showing output view indented descendants Die Kunde in der Ausgabeansicht eingerückt anzeigen &Close Window Fenster &schließen Close this window Dieses Fenster schließen &File &Datei &Edit &Bearbeiten &Node &Knoten &Data Da&ten &Tools &Extras &View &Ansicht &Window &Fenster &Help &Hilfe Start Incremental Search Starte inkrementelle Suche Next Incremental Search Nächste inkrementelle Suche Previous Incremental Search Vorherige inkrementelle Suche Show &Breadcrumb View Zeige &Breadcrumb Ansicht Toggle showing breadcrumb ancestor view Umschalten zu Breadcrumb Vorfahren Ansicht Show Output &Descendants Kinder in der Ausgabe mit anzeigen Fo&rmat Fo&rmat colorset Dialog background color Dialog für Hintergrundfarbe Dialog text color Dialog für Textfarbe Text widget background color Hintergrundfarbe für Textfelder Text widget foreground color Vordergrundfarbe für Textfelder Selected item background color Hintergrundfarbe des Eintrags Selected item text color Vordergrundfarbe des Eintragstextes Link text color Textfarbe von Links Tool tip background color Hintergrundfarbe für Tooltips Tool tip foreground color Vordergrundfarbe für Tooltips Button background color Button Hintergrundfarbe Button text color Button Textfarbe Disabled text foreground color Textfarbe deaktivieren Disabled button text color Farbe für nicht verfügbare Funktionen Color Settings Farbeinstellungen Color Theme unfinished">Farbschema Default system theme (Voreingestelltes) Systemthema Dark theme Dunkles Thema Custom theme Anwender-definiertes Thema &OK &OK &Cancel &Abbrechen Custom Colors Anwender-definierte Farben Theme Colors Farben des Themas Select {0} color {0} Farben auswählen TreeLine-3.2.1/working/translations/treeline_es.ts000066400000000000000000005732611506556630100223200ustar00rootroot00000000000000 conditional starts with comienza con ends with termina con contains contiene True Verdadero False Falso and y or o [All Types] [Todos los tipos] Node Type Tipo de nodo &Add New Rule Añadir &Nueva Regla &Remove Rule &Eliminar Regla &OK &OK &Cancel &Cancelar Find &Previous B&uscar Anterior Find &Next Buscar &Siguiente &Filter &Filtro &End Filter &Terminar filtro &Close &Cerrar No conditional matches were found Coincidencias condicionales no encontradas Rule {0} Regla {0} Saved Rules Reglas Guardadas Name: Nombre: &Load Car&gar &Save Guar&dar &Delete &Borrar configdialog Configure Data Types Configurar Tipos de Datos T&ype List Lista de &Tipos Field &List Lista de &Campos &Field Config Configuración de &Campos &Show Advanced &Mostrar Avanzado &OK &OK &Apply &Aplicar &Reset &Reiniciar &Cancel &Cancelar Add or Remove Data Types Añadir o Quitar Datos de Tipos &New Type... &Nuevo Tipo... Co&py Type... Co&piar Tipo... &Delete Type &Eliminar tipo Add Type Añadir tipo Enter new type name: Establecer nombre del nuevo tipo: Rename Type Renombrar tipo Cannot delete data type being used by nodes No se puede eliminar un tipo de datos que esté siendo usado por algún nodo &Data Type Tipo de &Datos Icon Icono Change &Icon Cambiar &Icono Derived from &Generic Type Derivado del Tipo &Genérico Automatic Types Tipos Automáticos Modify Co&nditional Types Modificar Tipos Co&ndicionales Create Co&nditional Types Crear Tipos Co&ndicionales Set Types Conditionally Configurar Tipos Condicionalmente Name Nombre Type Tipo Move &Up Mover A&rriba Move Do&wn Mover Aba&jo &New Field... &Nuevo Campo... Add Field Añadir Campo Enter new field name: Introduzca el nombre del nuevo campo: Rename Field Renombrar Campo F&ield Cam&po Format &Help Ayuda sobre &Formato Extra Text Texto Adicional &Prefix P&refijo Suffi&x Sufi&jo Editor Height Altura del editor Num&ber of text lines Número de líneas de te&xto File Info Reference Referencia de información de archivo Parent Reference Referencia Padre Child Reference Referencia Hija Child Count Recuento de Hijos F&ield List &Lista de Campos Other Field References Otras Referencias de Campos Copy Type Copiar Tipo Set Data Type Icon Establecer el Icono del Tipo de Datos Clear &Select Borrar &Selección Typ&e Config Configurar &Tipo O&utput &Salida de Datos &Hide Advanced &Ocultar Avanzado Error - circular reference in math field equations Error - referencia circular en ecuaciones de campo matemático Rena&me Type... Renom&brar Tipo... &Derive from original &Derivado del original Rename from {} to: Renombrar de {} a: [None] no type set [Nada] Default Child &Type Tipo Hi&jo por Defecto Output Options Opciones de Salida Add &blank lines between nodes Agregar línea en &blanco entre nodos Allow &HTML rich text in format Permitir &HTML con formato de texto enriquecido Add text bullet&s Agregar &viñetas al texto Use a table for field &data Mostrar datos de campo en tab&la Combination && Child List Output &Separator Combinación && &separador lista de hijos de Salida None Nada Modify &Field List Modificar &Lista de Campos Sort Key Clave de Clasificación Move U&p Mo&ver Arriba Rena&me Field... Renombrar Cam&po... Dele&te Field &Borrar Campo Sort &Keys... Ord&enar Claves... fwd Adelante rev Atrás &Field Type Tip&o de Campo Outpu&t Format Formato de Sa&lida Default &Value for New Nodes &Valor por Defecto para Nuevos Nodos Math Equation Ecuación matemática Define Equation Definir Ecuación &Title Format &Formato de Título Out&put Format &Formato de Salida Reference Le&vel Niv&el de Referencia Refere&nce Type Tipo de Refere&ncia The name cannot be empty El nombre no puede estar vacío The name must start with a letter El nombre debe comenzar con una letra The name cannot start with "xml" El nombre no puede comenzar con "xml" The name cannot contain spaces El nombre no puede contener espacios The following characters are not allowed: {} Los siguientes caracteres no están permitidos: {} The name was already used El nombre ya está en uso forward adelante reverse atrás Sort Key Fields Ordenar Campos Clave Available &Fields Campos &Disponibles &Sort Criteria C&riterio de Ordenación Field Campo Direction Dirección &Move Down Mover Aba&jo Flip &Direction Cam&biar Dirección Self Reference Autoreferencia Root Reference Referencia Raíz Date Result Resultado de Fecha Time Result Resultado de Tiempo add sumar subtract restar multiply multiplicar divide dividir floor divide división por redondeo modulus módulo power potencia sum of items suma de ítems maximum máximo minimum mínimo average promedio absolute value valor absoluto square root raíz cuadrada natural logarithm logaritmo natural base-10 logarithm logaritmo en base 10 factorial factorial round to num digits redondear a número de dígitos lower integer entero menor higher integer entero mayor truncated integer entero truncado floating point punto flotante sine of radians seno de radián cosine of radians coseno de radián tangent of radians Tangente de Radián arc sine arcoseno arc cosine arcocoseno arc tangent arcotangente radians to degrees radianes a grados degrees to radians grados a radianes pi constant número pi (constante) natural log constant constante logaritmo natural Define Math Field Equation Definir el Campo de Ecuación Matemática Field References Referencias de Campo Reference &Level Referencia de &Nivel Reference &Type Referencia de &Tipo Available &Field List Lista de &Campos Disponible &Result Type &Resultado Tipo Description Descripción &Equation &Ecuación Equation error: {} Erron en ecuación: {} Boolean Result Resultado Booleano Text Result Texto Resultante Arithmetic Operators Operadores Aritméticos Comparison Operators Operadores Comparativos Text Operators Operadores de Texto equal to igual a less than menor que greater than mayor que less than or equal to menor o igual que greater than or equal to mayor o igual que not equal to distinto a true value, condition, false value valor verdadero, condición, valor falso true if 1st text arg starts with 2nd arg verdadero si el argumentdo del primer texto comienza con un segundo argumento true if 1st text arg ends with 2nd arg verdadero si el argumentdo del primer texto termina con un segundo argumento true if 1st text arg contains 2nd arg verdadero si el argumentdo del primer texto contiene un segundo argumento concatenate text concatenar texto join text using 1st arg as separator unir texto usando como primer argumento un separador convert text to upper case convertir texto a mayúsculas convert text to lower case convertir texto a minúsculas in 1st arg, replace 2nd arg with 3rd arg en primer argumento, reemplazar segundo argumento con tercer argumento Operations Operaciones O&perator Type Tipo de O&perador Oper&ator List Lista de Oper&adores logical and lógico y logical or lógico o Output HTML Salida HTML Evaluate &HTML tags Evaluar etiquetas &HTML Child Type Limits Límites de los Tipos Hijo [All Types Available] [Todos los Tipos Disponibles] &Select All &Seleccionar Todo Select &None Seleccionar &Ninguno Number Result Resultado Numérico Count Number of Children dataeditors Today's &Date Fecha de &Hoy &Open Link &Abrir Enlace Open &Folder Abrir &Carpeta External Link Enlace Externo Scheme Esquema &Browse for File &Seleccionar Archivo File Path Type Tipo de ruta de archivo Absolute Absoluta Relative Relativa Address Dirección Display Name Mostrar Nombre &OK &OK &Cancel &Cancelar TreeLine - External Link File TreeLine - Enlace a archivo externo &Go to Target &Ir al Destino Internal Link Enlace Interno &Open Picture &Abrir Imagen Picture Link Enlace de Imagen TreeLine - Picture File TreeLine - Archivo de Imagen Set to &Now Establecer A&hora Clear &Link Borrar En&lace (Click link target in tree) (Clicar objeto a enlazar en el árbol) link enlace exports Bookmarks Favoritos TreeLine - Export HTML TreeLine - Exportar HTML TreeLine - Export Text Titles TreeLine - Exportar Textos de Títulos TreeLine - Export Plain Text TreeLine - Exportar Texto Plano TreeLine - Export Text Tables TreeLine - Exportar Tablas de Texto TreeLine - Export Generic XML TreeLine - Exportar XML Genérico TreeLine - Export TreeLine Subtree TreeLine - Exportar Subárbol TreeLine TreeLine - Export ODF Text Exportar Texto ODF TreeLine - Export HTML Bookmarks TreeLine - Exportar Favoritos HTML TreeLine - Export XBEL Bookmarks TreeLine - Exportar Favoritos XBEL &HTML &HTML &Text &Texto &ODF Outline &ODF Texto (esquema) Book&marks &Favoritos &Single HTML page Página HTML &Simple Single &HTML page with navigation pane &Página HTML simple con panel de navegación Multiple HTML &pages with navigation pane &Multiples páginas HTML con panel de navegación Multiple HTML &data tables Múltiples tablas de datos &HTML &Tabbed title text &Texto con tabulación por títulos &Unformatted output of all text &Salida sin formato para todo el texto &HTML format bookmarks Formato &HTML de favoritos &XBEL format bookmarks Formato &XBEL de favoritos File Export Exportar Archivo Choose export format type Seleccionar tipo de formato para exportar Choose export format subtype Seleccionar subtipo de formato para exportar Choose export options Seleccionar opciones para exportar What to Export Qué exportar &Entire tree &Todo el Árbol Selected &branches &Ramas Seleccionadas Selected &nodes &Nodos Seleccionados Other Options Otras Opciones &Only open node children Abrir s&olo nodos hijos Include &print header && footer Incluir im&presión de encabezado y pie &Columns &Columnas Navigation pane &levels Nive&les del Panel de Navegación Error - export template files not found. Check your TreeLine installation. Error - Exportar archivos de plantilla no encontrados. Verifique la instalación de su TreeLine. Error - cannot link to unsaved TreeLine file. Save the file and retry. Error: No se puede vincular al archivo TreeLine no guardado. Guarde el archivo y vuelva a intentarlo. Warning - no relative path from "{0}" to "{1}". Continue with absolute path? Advertencia: no hay una ruta relativa entre "{0}" y "{1}". Continuar con la ruta absoluta? Parent Padre Tree&Line Tree&Line &XML (generic) &XML (genérico) Live tree view, linked to TreeLine file (for web server) Vista de árbol en tiempo real, vinculada al archivo TreeLine (para servidor web) Live tree view, single file (embedded data) Vista de árbol en tiempo real, archivo único (datos incrustados) &Comma delimited (CSV) table of descendants (level numbers) Tabla &de descendientes delimitada por comas (CSV) (número de niveles) Comma &delimited (CSV) table of children (single level) T&abla de hijos delimitada por comas (CSV) (nivel único) Tab &delimited table of children (&single level) Ta&bla delimitada por tabulaciones según nodos hijos (nivel único) &Old TreeLine (2.0.x) &Antiguos TreeLine (2.0.x) &TreeLine Subtree &Subárbol TreeLine &Include root nodes &Incluir noddos principales Must select nodes prior to export Debe seleccionar nodos antes de exportar fieldformat yes/no sí/no true/false verdadero/falso T/F V/F Y/N S/N Text Texto HtmlText Texto Html OneLineText Texto de una línea SpacedText Texto espaciado Number Número Math Matemáticas Numbering Numeración Boolean Booleano Date Fecha Time Hora Choice Elección AutoChoice AutoElección Combination Combinación AutoCombination AutoCombinación ExternalLink Enlace Externo InternalLink EnlaceInterno Picture Imagen RegularExpression Expresión regular Now Ahora Optional Digit # Dígito Opcional # Required Digit 0 Dígito Requerido 0 Digit or Space (external) <space> Dígito o Espacio (externo) <space> Decimal Point . Punto Decimal . Decimal Comma , Coma Decimal , Space Separator (internal) <space> Separador Espacio (interno) <space> Optional Sign - Signo Opcional - Required Sign + Signo Requerido + Exponent (capital) E Exponente (mayúscula) E Exponent (small) e Exponente (minúscula) e Number 1 Número 1 Capital Letter A Mayúsculas A Small Letter a Minúsculas a Capital Roman Numeral I Números Romanos (mayúsculas) I Small Roman Numeral i Números romanos (minúsculas) i Level Separator / Separador de nivel / Section Separator . Separador de sección . "/" Character // "/" Carácter // "." Character .. "." Carácter .. Outline Example I../A../1../a)/i) Ejemplo de esquema I../A../1../a)/i) Section Example 1.1.1.1 Ejemplo de sección 1.1.1.1 Separator / Separador / Example 1/2/3/4 Ejemplo 1/2/3/4 Any Character . Cualquier Carácter . End of Text $ Final del Texto $ 0 Or More Repetitions * 0 o más repeticiones * 1 Or More Repetitions + 1 o más repeticiones + 0 Or 1 Repetitions ? 0 ó 1 Repeticiones ? Set of Numbers [0-9] Conjunto de Números [0-9] Lower Case Letters [a-z] Minúsculas [a-z] Upper Case Letters [A-Z] Mayúsculas [A-Z] Not a Number [^0-9] No es un número [^0-9] Or | O | Escape a Special Character \ Escape carácter especial \ DateTime Fecha y hora Day (1 or 2 digits) %-d Día (1 ó 2 dígitos) %-d Day (2 digits) %d Día (2 dígitos) %d Weekday Abbreviation %a Día de la semana (abreviado) %a Weekday Name %A Día de la semana %A Month (1 or 2 digits) %-m Mes (1 o 2 dígitos) %-m Month (2 digits) %m Mes (2 dígitos) %m Month Abbreviation %b Mes (abreviado) %b Month Name %B Mes (nombre completo) %B Year (2 digits) %y Año (2 dígitos) %y Year (4 digits) %Y Año (4 dígitos) %Y Week Number (0 to 53) %-U Semana (0 a 53) %-U Day of year (1 to 366) %-j Día del año (1 a 366) %-j Hour (0-23, 1 or 2 digits) %-H Hora (0-23, 1 ó 2 dígitos) %-H Hour (00-23, 2 digits) %H Hora (00-23, 2 dígitos) %H Hour (1-12, 1 or 2 digits) %-I Hora (1-12, 1 ó 2 dígitos) %-I Hour (01-12, 2 digits) %I Hora (01-12, 2 dígitos) %I Minute (1 or 2 digits) %-M Minutos (1 ó 2 dígitos) %-M Minute (2 digits) %M Minutos (2 dígitos) %M Second (1 or 2 digits) %-S Segundos (1 ó 2 dígitos) %-S Second (2 digits) %S Segundos (2 dígitos) %S Microseconds (6 digits) %f Microsegundos (6 dígitos) %f AM/PM %p AM/PM %p Comma Separator \, Separador Coma \, Dot Separator \. Separador Punto \. DescendantCount Cuenta Descendiente genboolean true verdadero false falso yes no no globalref TreeLine Files Archivos TreeLine TreeLine Files - Compressed Archivos TreeLine - Comprimido TreeLine Files - Encrypted Archivos TreeLine - Encriptado All Files Todos los Archivos HTML Files Archivos HTML Text Files Archivos de Texto XML Files Archivos XML ODF Text Files Archivos de Texto ODF Treepad Files Archivos de Treepad PDF Files Archivos PDF CSV (Comma Delimited) Files Archivos CSV (Delimitado por Comas) All TreeLine Files Todos los Archivos TreeLine Old TreeLine Files Archivos TreeLine Antiguos helpview &Back &Volver &Forward &Siguiente &Home &Inicio Find: Buscar: Find &Previous Buscar &Anterior Find &Next &Buscar Siguiente Text string not found Cadena de texto no encontrada Tools Herramientas imports &Tab indented text, one node per line &Sangrado de texto por tabulaciones, un nodo por línea Tab delimited text table with header &row Tabl&a de texto delimitada por tabulaciones con fila de encabezado Plain text &paragraphs (blank line delimited) Texto &plano en párrafos (delimitado por línea en blanco) Treepad &file (text nodes only) &Archivo Treepad (únicamente nodos de texto) &Generic XML (non-TreeLine file) XML &genérico (No es un archivo TreeLine) Open &Document (ODF) outline Open &Document (ODF) &HTML bookmarks (Mozilla Format) &HTML favoritos (Formato Mozilla) &XML bookmarks (XBEL format) Favoritos en &XML (Formato XBEL) FOLDER CARPETA BOOKMARK FAVORITO SEPARATOR SEPARADOR Link Enlace Text Texto Import File Importar Archivo Choose Import Method Escoger Método de Importación Invalid File Archivo no Válido "{0}" is not a valid TreeLine file. Use an import filter? "{0}" no es un archivo válido TreeLine. ¿Usar filtro de importación de archivo? TreeLine - Import File TreeLine - Importar archivo Error - could not read file {0} Error-no se puede leer archivo {0} Error - improper format in {0} Error - formato incorrecto en {0} TABLE TABLA Bookmarks Favoritos Too many entries on Line {0} Demasiadas entradas en la Línea {0} Plain text, one &node per line (CR delimited) Text&o plano, un &nodo por línea (delimitado por retorno de carro -CR-) Bad CSV format on Line {0} Formato CSV.erróneo en Línea {0} Co&mma delimited (CSV) text table with level column && header row T&exto delimitado por comas (CSV) tabla de texto con nivel de columna y fila de encabezado Comma delimited (CSV) text table &with header row Texto &delimitado por comas (CSV) tabla con fila de encabezado Other Otro Old Tree&Line File (1.x or 2.x) Archivo Antiguo de Tree&Line (1.x o 2.x) Invalid level number on line {0} Número de nivel no válido en la línea {0} Invalid level structure Estructura de nivel no válida No headings found matheval Illegal "{}" characters Caracteres "{}" no permitidos Child references must be combined in a function Las referencias secundarias deben combinarse en una función Illegal syntax in equation Sintaxis ilegar en la ecuación Illegal function present: {0} Función ilegal presente: {0} Illegal object type or operator: {0} Tipo de objeto u operador no permitido: {0} Invalid field modifiers miscdialogs &OK &OK &Cancel &Cancelar Fields Campos File Properties Propiedades de Archivo File Storage Almacenamiento de Archivos &Use file compression &Comprimir Archivo Use file &encryption &Encriptar Archivo Spell Check Comprobación de la ortografía Language code or dictionary (optional) Código de idioma o diccionario (opcional) Math Fields Campos Matemáticos &Treat blank fields as zeros Considerar los espacios en blanco como ceros (&0) Encrypted File Password Contraseña del Archivo Encriptado Type Password for "{0}": Escriba la Contraseña para "{0}": Type Password: Escriba la Contraseña: Re-Type Password: Escriba de nuevo la contraseña: Remember password during this session Recordar la contraseña durante esta sesión Zero-length passwords are not permitted No se permiten contraseñas de longitud cero Re-typed password did not match La contraseña reescrita no coincide Default - Single Line Text Predeterminado - Texto Simple &Search Text &Buscar texto What to Search Dónde Buscar Full &data En to&do &Titles only Sólo en &títulos How to Search Cómo Buscar &Key words &Contiene Key full &words Texto E&xacto F&ull phrase Frase co&mpleta &Regular expression Exp&resión regular Find Buscar Find &Previous Buscar &Anterior Find &Next Buscar &Siguiente Filter Filtro &Filter &Filtro &End Filter C&errar Filtro &Close &Cerrar Error - invalid regular expression Error - Expresión regular no válida Search string "{0}" not found Buscar cadena "{0}". No encontrada Find and Replace Buscar y reemplazar Replacement &Text Reemplazar &Texto Any &match Co&ntiene Full &words Coinci&de Re&gular expression Expresión re&gular &Node Type Tipo de &Nodo N&ode Fields Campos de N&odo &Find Next &Buscar Siguiente &Replace &Reemplazar Replace &All Reemplaz&ar Todo [All Types] [Todos los tipos] [All Fields] [Todos los campos] Search text "{0}" not found Búsqueda del texto "{0}" no encontrado Error - replacement failed Error - reemplazo fallido Replaced {0} matches Reemplazadas {0} coincidencias Sort Nodes Ordenar Nodos What to Sort Qué ordenar &Entire tree Árbol compl&eto Selected &branches Ramas &Seleccionadas Selection's childre&n &Hijos seleccionados Selection's &siblings Her&manos seleccionados Sort Method Método de ordenado &Predefined Key Fields Nombres de Campos &Predefinidos Node &Titles &Títulos de Nodos Sort Direction Dirección de Ordenado &Forward &Adelante &Reverse At&rás &Apply A&plicar Update Node Numbering Actualizar Numeración de Nodo What to Update Qué Actualizar &Selection's children &Selección de Hijos Root Node Nodo Principal Include top-level nodes Incluir nodos de nivel superior Handling Nodes without Numbering Fields Manejar nodos sin Campos de Numeración &Ignore and skip &Ignorar y omitir &Restart numbers for next siblings &Reiniciar números para los siguientes hermanos Reserve &numbers Reserva &números TreeLine Numbering Numeración TreeLine No numbering fields were found in data types No se encontraron campos de numeración en los tipos de datos File Menu Menú de Archivo File Archivo Edit Menu Menú Edición Edit Editar Node Menu Menú de Nodo Node Nodo Data Menu Menú de datos Data Datos Tools Menu Menú de Herramientas Tools Herramientas View Menu Menú Ver View Ver Window Menu Menú Ventana Window Ventana Help Menu Menú Ayuda Help Ayuda Keyboard Shortcuts Atajos de Teclado &Restore Defaults &Restaurar Valores por &Defecto Key {0} is already used Clave {0} ya está en uso Clear &Key Borrar Cla&ve --Separator-- --Separador-- Customize Toolbars Personalizar Barra de Herramientas Toolbar &Size Tamaño Barra de Herramienta&s Small Icons Iconos Pequeños Large Icons Iconos Grandes Toolbar Quantity Cantidad de barras de herramientas &Toolbars Barras de herramien&tas A&vailable Commands Comandos Dis&ponibles Tool&bar Commands Comandos de la &barra de herramientas Move &Up Mover &Arriba Move &Down Mover Aba&jo Tree View Font Fuente del Árbol Output View Font Fuente de Salida Editor View Font Fuente del Editor No menu No.menu TreeLine - Serious Error TreeLine - Error Grave A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. Se ha producido un error grave. TreeLine podría estar en un estado inestable. Se recomienda guardar cualquier cambio de archivo con otro nombre de archivo y reiniciar TreeLine. La información de depuración que se muestra a continuación se puede copiar y enviar por correo electrónico a doug101@bellz.org junto con una explicación de las circunstancias del error. Format Menu Menú Formato Format Formato Customize Fonts Personalizar Fuentes &Use system default font &Usar fuente por defecto del sistema App Default Font Fuente por defecto de la aplicación &Use app default font &Usar la fuente predeterminada de la aplicación Externally Modified File &Overwrite File &Cancel Save File was externally modified at {} nodeformat Name Nombre optiondefaults Monday Lunes Tuesday Martes Wednesday Miércoles Thursday Jueves Friday Viernes Saturday Sábado Sunday Domingo Startup Condition Condición de Inicio Automatically open last file used Abrir automáticamente el último archivo usado Show descendants in output view Mostrar hijos en la vista de salida Restore tree view states of recent files Restaurar estados de vista en árbol de archivos recientes Restore previous window geometry Restaurar la geometría de la ventana anterior Features Available Funcionalidades disponibles Open files in new windows Abrir archivos en una nueva ventana Click node to rename Clicar en nodo para renombrar Rename new nodes when created Renombrar los nodos nuevos cuando sean creados Tree drag && drop available Disponible la opción de pulsar y arrastrar en el árbol Show icons in the tree view Mostrar iconos en la vista de árbol Show math fields in the Data Edit view Mostrar campos matemáticos en la vista de Edición de Datos Show numbering fields in the Data Edit view Mostrar campos de numeración en la vista de Edición de Datos Undo Memory Memoria usada por la opción "deshacer" Number of undo levels Número de niveles de deshacer Auto Save Grabación automática Minutes between saves (set to 0 to disable) Minutos entre respaldos (seleccione 0 para desactivar) Recent Files Archivos recientes Number of recent files in the file menu Cantidad de archivos recientes en el menú de archivo Data Editor Formats Formatos del editor de datos Times Horas Dates Fechas First day of week Primer día de la semana Appearance Apariencia Child indent offset (in font height units) Corrección de sangrado de hijos (en unidades de altura de fuente) Show breadcrumb ancestor view Mostrar panel de navegación Show child pane in right hand views Motrar paneles hijos en la vista derecha Remove inaccessible recent file entries Eliminar archivos inaccesibles en la vista de archivos recientes Activate data editors on mouse hover Activar editores de datos cuando el puntero del ratón esté encima Minimize application to system tray Minimiza aplicación a la bandeja del sistema Indent (pretty print) TreeLine JSON files Sangrado (mejor impresión) Archivos TreeLine JSON Limit data editor height to window size options Choose configuration file location Elija la ubicación del archivo de configuración User's home directory (recommended) Directorio de inicio de usuario (recomendado) Program directory (for portable use) Carpeta del programa (para uso portable) &OK &Aceptar &Cancel &Cancelar printdata Error initializing printer Error inicializando la impresora TreeLine - Export PDF TreeLine - Exportar a PDF Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Advertencia: configuración de tamaño de página y margen no admitida en la impresora actual. ¿Guardar los ajustes de página? Warning: Page size setting unsupported on current printer. Save adjustment? Advertencia: configuración de tamaño de página no admitida en la impresora actual. ¿Guardar ajustes? Warning: Margin settings unsupported on current printer. Save adjustments? Advertencia: configuración de margen no compatible en la impresora actual. ¿Guardar los ajustes? printdialogs Print Preview Vista Previa de Impresión &Print... &Imprimir... &General Options Opciones &Generales &Font Selection Selección de &Fuente &Header/Footer &Encabezado y pie Print Pre&view... &Vista Previa... &OK &OK &Cancel &Cancelar What to print Qué imprimir &Entire tree &Árbol completo Selected &branches &Ramas seleccionadas Selected &nodes &Nodos seleccionados Features Características &Include root node Incluir el nodo rai&z &Keep first child with parent &Mantener el primer nodo hijo con el padre Letter (8.5 x 11 in.) Carta (8.5 x 11 in.) Legal (8.5 x 14 in.) Legal (8.5 x 14 in.) Tabloid (11 x 17 in.) Tabloide (11 x 17 in.) A3 (279 x 420 mm) A3 (279 x 420 mm) A4 (210 x 297 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A5 (148 x 210 mm) Paper &Size Tamaño del Pape&l Orientation Orientación &Units &Unidades Columns Columnas &Number of columns &Número de columnas Default Font Fuente predeterminada Select Font Seleccionar Fuente &Font &Fuente Font st&yle E&stilo de fuente Sample Ejemplo &Header Left Encabezado I&zquierdo Header C&enter Encabezado cen&trado Footer &Left Pie Iz&quierdo Footer Ce&nter Pie ce&ntrado Fiel&ds Campo&s Header and Footer Encabezado y pie de página Extra Text Texto adicional &Prefix &Prefijo Format &Help A&yuda de Formato Fit Width Ajuste de ancho Fit Page Ajuste de página Zoom In Zoom Aumentar Zoom Out Zorrm Reducir Previous Page Página anterior Next Page Página Siguiente Single Page Página sencilla Facing Pages Páginas enfrentadas Print Setup Configuración de Impresión Print Imprimir Printing Setup Configuración de Impresión Page &Setup Configuración de &Página Included Nodes Nodos Incluídos Onl&y open node children Incluir solo nodos &hijos &Draw lines to children &Dibujar líneas para los nodos hijos Indent Sangrar Indent Offse&t (line height units) Sangrado de &Salida (unidades de altura de línea) Custom Size Tamaño Personalizado Inches (in) Pulgadas (in) Millimeters (mm) Milímetros (mm) Centimeters (cm) Centímetros (cm) &Width: A&nchura: Height: Altura: Portra&it Retra&to Lan&dscape Paisa&je Margins Márgenes &Left: Iz&quierda: &Top: A&rriba: &Right: Derec&ha: &Bottom: A&bajo: He&ader: Encabe&zado: Foot&er: &Pie: Space between colu&mns Espacio entre colu&mnas &Use TreeLine output view font &Usar la misma que haya configurada en "Salida de Datos" de TreeLine Si&ze &Tamaño AaBbCcDdEeFfGg...TtUuVvWvXxYyZz AaBbCcDdEeFfGg...TtUuVvWvXxYyZz Header &Right Encabezado &Derecho Footer Righ&t Pie De&recho Field For&mat For&mato de Campo Field Format for "{0}" Formato de Campo para "{0}" Output &Format Salida &Formato &Suffix &Sufijo Error: Page size or margins are invalid Error: Tamaño de página o márgenes inválidos TreeLine PDF Printer TreeLine Impresora PDF Select &Printer Seleccionar Im&presora recentfiles spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? No se pudo encontrar aspell.exe, ispell.exe o hunspell.exe ¿Buscar la ubicación? Spell Check Error Error ortográfico Locate aspell.exe, ipsell.exe or hunspell.exe Ubique aspell.exe, ipsell.exe o hunspell.exe Program (*.exe) Programa (*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed Error de comprobación ortográfica TreeLine Comprobar que esté instalado aspell, ispell o hunspell TreeLine Spell Check Comprobación ortográfica de TreeLIne Finished spell checking Comprobación ortográfica finalizada Spell Check Comprobación de la ortografía Not in Dictionary No está en el diccionario Word: Palabra: Context: Contexto: Suggestions Sugerencias Ignor&e Ignor&ar &Ignore All &Ignorar todo &Add &Añadir Add &Lowercase Añadir &minúscula &Replace &Reemplazar Re&place All Reem&plazar todo &Cancel &Cancelar Finished checking the branch Continue from the top? Terminada revisión de la rama Continuar desde la parte superior? titlelistview Select in Tree Seleccionar en Árbol treeformats DEFAULT PREDETERMINADO FILE ARCHIVO TYPE TIPO FIELD CAMPO FieldType TipoCampo TitleFormat OutputFormat SpaceBetween FormatHtml Bullets Table ChildType Icon Icono GenericType ConditionalRule ListSeparator ChildTypeLimit Format Formato Prefix Suffix InitialValue NumLines SortKeyNum SortForward EvalHtml treelocalcontrol Error - could not delete backup file {} Error - No se puede borrar el archivo de respaldo {} Save changes to {}? ¿Guardar cambios en {}? Save changes? ¿Guardar cambios? &Save &Guardar Save File Guardar archivo Save the current file Guardar el archivo actual Save &As... Guardar &Como... Save the file with a new name Guardar el archivo con un nombre nuevo &Export... &Exportar... Export the file in various other formats Exportar el archivo en varios formatos Prop&erties... &Propiedades... Set file parameters like compression and encryption Establecer parámetros de archivo como compresión y encriptación P&rint Setup... Config&uración de Impresión... Set margins, page size and other printing options Establecer márgenes, tamaño de página y otras opciones de impresión Print Pre&view... &Vista Previa de Impresión... Show a preview of printing results Vista previa de los resultados de impresión &Print... &Imprimir... Print tree output based on current options Imprimir salida de árbol en base a las opciones actuales Print &to PDF... Imprimir a PD&F... Export to PDF with current printing options Exportar a PDF con las opciones de impresión actuales &Undo &Deshacer Undo the previous action Deshacer la acción anterior &Redo &Rehacer Redo the previous undo Rehacer la última acción sobre la que se ha aplicado deshacer Cu&t Cor&tar Cut the branch or text to the clipboard Cortar la rama o el texto al portapapeles &Copy &Copiar Copy the branch or text to the clipboard Copiar la rama o texto al portapapeles &Paste &Pegar Paste nodes or text from the clipboard Pegar nodos o texto desde el portapapeles Paste non-formatted text from the clipboard Pegar texto sin formato del portapapeles &Bold Font &Negrita Set the current or selected font to bold Establecer la fuente actual o seleccionada en negrita &Italic Font &Cursiva Set the current or selected font to italic Establecer la fuente actual o seleccionada en cursiva U&nderline Font &Subrayado Set the current or selected font to underline Establecer la fuente actual o seleccionada para subrayar &Font Size &Tamaño de Fuente Set size of the current or selected text Establecer el tamaño del texto actual o seleccionado Small Pequeño Default Predeterminado Large Grande Larger Más grande Largest El más grande Set Font Size Definir tamaño de fuente Font C&olor... Color de &Fuente... Set the color of the current or selected text Establecer el color del texto actual o seleccionado &External Link... Enlace &Externo... Add or modify an extrnal web link Añadir o modificar un enlace web externo Internal &Link... Enlace &Interno... Add or modify an internal node link Añadir o modificar un enlace interno a nodo Clear For&matting &Borrar Formato Clear current or selected text formatting Borrar actual o seleccionado formato de texto &Rename &Renombrar Rename the current tree entry title Renombrar título completo del árbol en uso Insert Sibling &Before Añadir &Hermano Antes Insert new sibling before selection Añadir nuevo hermano antes de la selección Insert Sibling &After Añadir Hermano &Después Insert new sibling after selection Añadir nuevo hermano despues de la selección Add &Child &Añadir Hijo Add new child to selected parent Añadir nuevo hijo al padre seleccionado &Delete Node &Eliminar Nodo Delete the selected nodes Eliminar los nodos seleccionados &Indent Node &Sangrar Nodos Indent the selected nodes Sangrar los nodos seleccionados &Unindent Node Deshacer Sangrado de &Nodo Unindent the selected nodes Eliminar sangrado de los nodos seleccionados &Move Up Mover A&rriba Move the selected nodes up Desplazar hacia arriba los nodos seleccionados M&ove Down Mover Aba&jo Move the selected nodes down Desplazar hacia abajo los nodos seleccionados Move &First Mover al &Principio Move the selected nodes to be the first children Mover nodos seleccionados para ser los primeros hijos Move &Last Mover al &Final Move the selected nodes to be the last children Mover nodos seleccionados para ser los últimos hijos &Set Node Type &Establecer Tipo de Nodo Set the node type for selected nodes Establecer tipo de nodo para los nodos seleccionados Set Node Type Establecer tipo de nodo Copy Types from &File... &Copiar Tipos desde Archivo... Copy the configuration from another TreeLine file Copiar la configuración desde otro archivo de TreeLine Flatten &by Category &Acoplar por Categoría Collapse descendants by merging fields Contraer descendientes cuando se fusionen campos Add Category &Level... Añadir Ni&vel de Categoría... Insert category nodes above children Añadir los nodos con las categorías por encima de los hijos &Spell Check... Corrector &Ortográfico... &New Window &Nueva Ventana Open a new window for the same file Abrir nueva ventana para el mismo archivo Error - could not write to {} Error - No se pudo escribir en {} TreeLine - Save As TreeLine - Guardar como Error - could not write to file Error - no se pudo escribir en el archivo TreeLine - Open Configuration File TreeLine - Abrir archivo de configuración Error - could not read file {0} Error: no se pudo leer el archivo {0} Cannot expand without common fields No es posible expandir sin campos comunes Category Fields Campos de las categorías Select fields for new level Seleccionar campos para nuevo nivel File saved Archivo guardado Pa&ste Plain Text Pegar Texto sin &Formato Paste C&hild Pegar &Hijo Paste a child node from the clipboard Pegar un nodo hijo desde el portapapeles Paste Sibling &Before Pegar Hermano &Antes Paste a sibling before selection Pegar hermano antes de la selección Paste Sibling &After Pegar Hermano Despué&s Paste a sibling after selection Pegar un hermano después de la selección Paste Cl&oned Child Pegar Hijo C&lonado Paste a child clone from the clipboard Pegar hijo clonado desde el portapapeles Paste Clo&ned Sibling Before Pegar Hermano Clo&nado Antes Paste a sibling clone before selection Pegar un clon hermano antes de la selección Paste Clone&d Sibling After Pegar Hermano Clonad&o Después Paste a sibling clone after selection Pegar un clon hermano después de la selección Clone All &Matched Nodes Clonar &Todos los Nodos Emparejados Convert all matching nodes into clones Convertir todos los nodos coincidentes en clones &Detach Clones &Separar Clones Detach all cloned nodes in current branches Separar todos los nodos clonados en las ramas actuales S&wap Category Levels &Intercambiar Niveles de Categoría Swap child and grandchild category nodes Intercambiar categoría nodos hijos y nietos Converted {0} branches into clones Convierte ramas {0} en clones No identical nodes found No existen nodos idénticos Warning - file corruption! Skipped bad child references in the following nodes: Advertencia: ¡archivo corrupto! Se omitieron referencias de elementos secundarios incorrectos en los siguientes nodos: Spell check the tree's text data Revisar los datos de texto del árbol &Regenerate References Re&generar Referencias Force update of all conditional types & math fields Forzar actualización de todos los tipos condicionales y campos matemáticos Insert &Date Insert current date as text St&rikethrough Font Set the current or selected font to strikethough treemaincontrol Warning: Could not create local socket Advertencia: no se pudo crear el socket local Error - could not write config file to {} Error - no se pudo escribir el archivo de configuración en {} Error - could not read file {0} Error: no se pudo leer el archivo {0} Backup file "{}" exists. A previous session may have crashed Existe un archivo de respaldo: "{}". Una sesión anterior puede haberse bloqueado &Restore Backup &Restaurar copia de seguridad &Delete Backup Eliminar copia de segurida&d &Cancel File Open &Cancelar archivo abierto Error - could not rename "{0}" to "{1}" Error: - no se pudo cambiar el nombre de "{0}" a "{1}" Error - could not remove backup file {} Error - no se pudo eliminar el archivo de copia de seguridad {} &New... &Nuevo... New File Archivo nuevo Start a new file Comenzar un archivo nuevo &Open... &Abrir... Open File Abrir archivo Open a file from disk Abrir un archivo desde el disco Open Sa&mple... Abrir Archivo de Eje&mplo... Open Sample Abrir ejemplo Open a sample file Abrir un archivo de ejemplo &Import... Importa&r... Open a non-TreeLine file Abriri un arhchivo no-TreeLine &Quit &Salir Exit the application Salir de la aplicación &Select All Seleccionar T&odo Select all text in an editor Seleccionar todo el texto en un editor &Configure Data Types... Configurar Tipos de &Datos... Modify data types, fields & output lines Modificar tipos de datos, campos y líneas de salida Sor&t Nodes... &Ordenar Nodos... Define node sort operations Definir operaciones de ordenación de nodos Update &Numbering... Actualizar &Numeración... Update node numbering fields Actualizar campos de numeración de nodos &Find Text... &Buscar Texto... Find text in node titles & data Buscar texto en títulos y datos de nodo &Conditional Find... Búsqueda &Condicional... Use field conditions to find nodes Use condiciones de campo para encontrar nodos Find and &Replace... Buscar y &Reemplazar... Replace text strings in node data Reemplazar cadenas de texto en datos de nodo &Text Filter... Filtro de &Texto... Filter nodes to only show text matches Filtrar nodos para mostrar solo coincidencias de texto C&onditional Filter... &Filtro Condicional... Use field conditions to filter nodes Usar condiciones de campo para filtrar nodos &General Options... Opciones &Generales... Set user preferences for all files Configurar las preferencias para todos los archivos Set &Keyboard Shortcuts... Establecer &Atajos de Teclado... Customize keyboard commands Personalizar comandos de teclado C&ustomize Toolbars... Personalizar Barras de &Herramientas... Customize toolbar buttons Personalizar botones de la barra de herramientas Customize Fo&nts... &Personalizar Fuentes... Customize fonts in various views Personalizar fuentes en varias vistas &Basic Usage... Uso &Básico... Display basic usage instructions Mostrar instrucciones de uso básico &Full Documentation... &Documentación completa... Open a TreeLine file with full documentation Abrir un archivo TreeLine con documentación completa &About TreeLine... &Acerca de TreeLine... Display version info about this program Mostrar información de versión de esta aplicación &Select Template &Seleccionar Plantilla TreeLine - Open File TreeLine - Abrir Archivo Open Sample File Abrir archivo de ejemplo &Select Sample &Seleccionar Ejemplo Conditional Find Búsqueda Condicional Conditional Filter Filtro Condicional General Options Opciones generales Error - basic help file not found Error - archivo de ayuda básica no encontrado TreeLine Basic Usage TreeLine Uso Básico Error - documentation file not found Error - archivo de documentación no encontrado Error - invalid TreeLine file {0} Error - archivo TreeLine no válido {0} TreeLine version {0} TreeLine version {0} written by {0} escrito por {} Library versions: Versiones de la biblioteca: missing directory Directorio no encontrado Show C&onfiguration Structure... Mostrar Confi&guración de Estructura... Show read-only visualization of type structure Mostrar visualización de solo lectura del tipo de estructura Custo&mize Colors... Customize GUI colors and themes treemodel treenode New Nuevo treestructure Main Principal treeview Filtering by "{0}", found {1} nodes Filtrando por "{0}", encontrados.{1} nodos Conditional filtering, found {0} nodes Filtrado condicional, encontrados {0} nodos Search for: Buscar: Search for: {0} Buscar {0} Search for: {0} (not found) Buscar {0} (no encontrado) Next: {0} Siguiente: {0} Next: {0} (not found) Siguiente: {0} (no encontrado) treewindow Data Output Salida de Datos Data Edit Editor de Datos Title List Lista de Títulos &Expand Full Branch &Expandir Toda la Rama Expand all children of the selected nodes Expandir todos los hijos de los nodos seleccionados &Collapse Full Branch &Reducir Toda la Rama Collapse all children of the selected nodes Reducir todos los hijos de los nodos seleccionados &Previous Selection Selección &Previa Return to the previous tree selection Volver a la selección de árbol anterior &Next Selection Selección &Siguiente Go to the next tree selection in history Ir a la siguiente selección de árbol en el historial Show Data &Output &Mostrar Salida de Datos Show data output in right view Mostrar la salida de datos en la vista derecha Show Data &Editor Mostrar Editor de &Datos Show data editor in right view Mostrar el editor de datos en la vista de la derecha Show &Title List Mostrar &Lista de Títulos Show title list in right view Mostrar la lista de títulos en la vista de la derecha &Show Child Pane Mostrar Panel &Hijo Toggle showing right-hand child views Alternar mostrando resultados Toggle showing output view indented descendants Alternar mostrando la vista de salida sangría de descendients &Close Window &Cerrar Ventana Close this window Cerrar esta ventana &File &Archivo &Edit &Editar &Node &Nodo &Data &Datos &Tools &Herramientas &View &Ver &Window Ven&tana &Help A&yuda Start Incremental Search Iniciar búsqueda incremental Next Incremental Search Búsqueda incremental siguiente Previous Incremental Search Búsqueda incremental anterior Show &Breadcrumb View Mostrar &vista panel de navegación Toggle showing breadcrumb ancestor view Alternar mostrando vista anterior de navegación Show Output &Descendants Mostrar Salida de Datos y Des&cendientes Fo&rmat &Formato colorset Dialog background color Dialog text color Text widget background color Text widget foreground color Selected item background color Selected item text color Link text color Tool tip background color Tool tip foreground color Button background color Button text color Disabled text foreground color Disabled button text color Color Settings Color Theme Color de Tema Default system theme Dark theme Custom theme &OK &OK &Cancel &Cancelar Custom Colors Theme Colors Select {0} color TreeLine-3.2.1/working/translations/treeline_fr.ts000066400000000000000000005666041506556630100223230ustar00rootroot00000000000000 conditional starts with commence avec ends with se termine par contains contient True Vrai False Faux and et or ou [All Types] Node Type &Add New Rule &Ajouter Nouvelle Règle &Remove Rule &Supprimer Règle &OK &OK &Cancel &Annuler Find &Previous Chercher &Précédent Find &Next Chercher &Suivant &Filter &End Filter &Close &Fermer No conditional matches were found Rule {0} Saved Rules Name: &Load &Save &Enregistrer &Delete configdialog Configure Data Types Paramètres du Type de Données T&ype List Liste des t&ypes Field &List &Liste des champs &Field Config Con&figuration des champs &Show Advanced Avancé&s &OK &OK &Apply &Appliquer &Reset &Réinitialiser &Cancel &Annuler Add or Remove Data Types Ajouter ou supprimer des Types de Données &New Type... &Nouveau Type... Co&py Type... Co&pier le type… &Delete Type &Supprimer Type Add Type Ajouter Type Enter new type name: Entrer un nouveau nom de type: Rename Type Renommer Type Cannot delete data type being used by nodes Impossible de supprimer un type de données qui est en cours d'utilisation par des nœuds &Data Type T&ype de Données Icon Icône Change &Icon Modifier l'&Icône Derived from &Generic Type Dérivé d'un Type &Générique Automatic Types Types Automatiques Modify Co&nditional Types Modifier un Type co&nditionnel Create Co&nditional Types Créer un Type Co&nditionnel Set Types Conditionally Configurer Types Sous Conditons Name Nom Type Type Move &Up Déplacer vers le &haut Move Do&wn Déplacer vers le &bas &New Field... &Nouveau Champ... Add Field Ajouter un champ Enter new field name: Entrer le nouveau nom du champ : Rename Field Renommer le champ F&ield C&hamp Format &Help Aide & formatage Extra Text Texte Supplémentaire &Prefix &Préfixe Suffi&x Suffi&xe Editor Height Hauteur de l'Editeur Num&ber of text lines Nom&bre de lignes de texte File Info Reference Références du Fichier Parent Reference Référence du Parent Child Reference Réference du Fils Child Count Nombre d'enfant F&ield List L&iste des champs Other Field References Références à d'autres champs Copy Type Copier Type Set Data Type Icon Configurer Icône Type de Données Clear &Select Effacer &Sélection Typ&e Config O&utput &Hide Advanced Error - circular reference in math field equations Rena&me Type... &Derive from original Rename from {} to: [None] no type set [Aucun] Default Child &Type Output Options Add &blank lines between nodes Allow &HTML rich text in format Add text bullet&s Use a table for field &data Combination && Child List Output &Separator None Aucun Modify &Field List Sort Key Move U&p Rena&me Field... Dele&te Field Sort &Keys... fwd rev &Field Type Outpu&t Format Default &Value for New Nodes Math Equation Define Equation &Title Format Out&put Format Reference Le&vel Refere&nce Type The name cannot be empty The name must start with a letter The name cannot start with "xml" The name cannot contain spaces The following characters are not allowed: {} The name was already used forward reverse Sort Key Fields Available &Fields &Sort Criteria Field Direction Direction &Move Down Flip &Direction Self Reference Root Reference Date Result Time Result add ajouter subtract multiply divide floor divide modulus power sum of items maximum minimum average absolute value square root natural logarithm base-10 logarithm factorial round to num digits lower integer higher integer truncated integer floating point sine of radians cosine of radians tangent of radians arc sine arc cosine arc tangent radians to degrees degrees to radians pi constant natural log constant Define Math Field Equation Field References Reference &Level Reference &Type Available &Field List &Result Type Description &Equation Equation error: {} Boolean Result Text Result Arithmetic Operators Comparison Operators Text Operators equal to less than greater than less than or equal to greater than or equal to not equal to true value, condition, false value true if 1st text arg starts with 2nd arg true if 1st text arg ends with 2nd arg true if 1st text arg contains 2nd arg concatenate text join text using 1st arg as separator convert text to upper case convert text to lower case in 1st arg, replace 2nd arg with 3rd arg Operations O&perator Type Oper&ator List logical and logical or Output HTML Evaluate &HTML tags Child Type Limits [All Types Available] &Select All Select &None Number Result Count Number of Children dataeditors Today's &Date &Open Link Open &Folder External Link Scheme &Browse for File File Path Type Absolute Relative Address Display Name &OK &OK &Cancel &Annuler TreeLine - External Link File &Go to Target Internal Link &Open Picture Picture Link TreeLine - Picture File Set to &Now Clear &Link (Click link target in tree) link exports Bookmarks Favoris TreeLine - Export HTML TreeLine - Export Text Titles TreeLine - Export Plain Text TreeLine - Export Text Tables TreeLine - Export Generic XML TreeLine - Export TreeLine Subtree TreeLine - Export ODF Text TreeLine - Export HTML Bookmarks TreeLine - Export XBEL Bookmarks &HTML &Text &ODF Outline Book&marks &Single HTML page Single &HTML page with navigation pane Multiple HTML &pages with navigation pane Multiple HTML &data tables &Tabbed title text &Texte des titres tabulés &Unformatted output of all text &HTML format bookmarks &XBEL format bookmarks File Export Choose export format type Choose export format subtype Choose export options What to Export Que faut−il exporter &Entire tree Arbre &Entier Selected &branches &Branches sélectionnées Selected &nodes &Nœuds sélectionnés Other Options &Only open node children Include &print header && footer &Columns Navigation pane &levels Error - export template files not found. Check your TreeLine installation. Error - cannot link to unsaved TreeLine file. Save the file and retry. Warning - no relative path from "{0}" to "{1}". Continue with absolute path? Parent Tree&Line &XML (generic) Live tree view, linked to TreeLine file (for web server) Live tree view, single file (embedded data) &Comma delimited (CSV) table of descendants (level numbers) Comma &delimited (CSV) table of children (single level) Tab &delimited table of children (&single level) &Old TreeLine (2.0.x) &TreeLine Subtree &Include root nodes Must select nodes prior to export fieldformat yes/no oui/non true/false vrai/faux T/F V/F Y/N O/N Text Texte HtmlText OneLineText SpacedText Number Nombre Math Numbering Boolean Booléen Date Date Time Heure Choice Choix AutoChoice ChoixAuto Combination Combinaison AutoCombination ExternalLink InternalLink LienInterne Picture Image RegularExpression Now Maintenant Optional Digit # Required Digit 0 Digit or Space (external) <space> Decimal Point . Decimal Comma , Space Separator (internal) <space> Optional Sign - Required Sign + Exponent (capital) E Exponent (small) e Number 1 Capital Letter A Small Letter a Capital Roman Numeral I Small Roman Numeral i Level Separator / Section Separator . "/" Character // "." Character .. Outline Example I../A../1../a)/i) Section Example 1.1.1.1 Separator / Example 1/2/3/4 Any Character . End of Text $ 0 Or More Repetitions * 1 Or More Repetitions + 0 Or 1 Repetitions ? Set of Numbers [0-9] Lower Case Letters [a-z] Upper Case Letters [A-Z] Not a Number [^0-9] Or | Escape a Special Character \ DateTime Day (1 or 2 digits) %-d Day (2 digits) %d Weekday Abbreviation %a Weekday Name %A Month (1 or 2 digits) %-m Month (2 digits) %m Month Abbreviation %b Month Name %B Year (2 digits) %y Year (4 digits) %Y Week Number (0 to 53) %-U Day of year (1 to 366) %-j Hour (0-23, 1 or 2 digits) %-H Hour (00-23, 2 digits) %H Hour (1-12, 1 or 2 digits) %-I Hour (01-12, 2 digits) %I Minute (1 or 2 digits) %-M Minute (2 digits) %M Second (1 or 2 digits) %-S Second (2 digits) %S Microseconds (6 digits) %f AM/PM %p Comma Separator \, Dot Separator \. DescendantCount genboolean true vrai false faux yes oui no non globalref TreeLine Files Fichiers TreeLine TreeLine Files - Compressed Fichiers TreeLine - Compressé TreeLine Files - Encrypted Fichiers TreeLine - Encrypté All Files HTML Files Text Files Fichiers Texte XML Files Fichiers XML ODF Text Files Fichier Texte ODF Treepad Files Fichiers Treepad PDF Files CSV (Comma Delimited) Files All TreeLine Files Old TreeLine Files helpview &Back &Précédent &Forward &Suivant &Home &Accueil Find: Chercher: Find &Previous Chercher &Précédent Find &Next Chercher &Suivant Text string not found Chaîne de caractères non trouvée Tools imports &Tab indented text, one node per line Tab delimited text table with header &row Plain text &paragraphs (blank line delimited) Treepad &file (text nodes only) &Fichier Treepad (noeuds texte seulement) &Generic XML (non-TreeLine file) Open &Document (ODF) outline &HTML bookmarks (Mozilla Format) &XML bookmarks (XBEL format) &XML favoris (format XBEL) FOLDER REPERTOIRE BOOKMARK FAVORIS SEPARATOR SEPARATEUR Link Lien Text Texte Import File Choose Import Method Invalid File "{0}" is not a valid TreeLine file. Use an import filter? TreeLine - Import File Error - could not read file {0} Error - improper format in {0} TABLE Bookmarks Favoris Too many entries on Line {0} Plain text, one &node per line (CR delimited) Bad CSV format on Line {0} Co&mma delimited (CSV) text table with level column && header row Comma delimited (CSV) text table &with header row Other Old Tree&Line File (1.x or 2.x) Invalid level number on line {0} Invalid level structure No headings found matheval Illegal "{}" characters Child references must be combined in a function Illegal syntax in equation Illegal function present: {0} Illegal object type or operator: {0} Invalid field modifiers miscdialogs &OK &OK &Cancel &Annuler Fields Champs File Properties File Storage Fichier &Use file compression Use file &encryption Spell Check Vérification orthographique Language code or dictionary (optional) Math Fields &Treat blank fields as zeros Encrypted File Password Mot de passe encrypté Type Password for "{0}": Type Password: Entrer le mot de passe: Re-Type Password: Entrer à nouveau le mot de passe: Remember password during this session Se souvenir du mot de passe pendant cette session Zero-length passwords are not permitted Les mots de passe de longueur zéro ne sont pas autorisés Re-typed password did not match Le mot de passe entré la deuxième fois ne correspond pas Default - Single Line Text &Search Text What to Search Full &data &Titles only How to Search &Key words Key full &words F&ull phrase &Regular expression Find Chercher Find &Previous Chercher &Précédent Find &Next Chercher &Suivant Filter &Filter &End Filter &Close &Fermer Error - invalid regular expression Search string "{0}" not found Find and Replace Replacement &Text Any &match Full &words Re&gular expression &Node Type N&ode Fields &Find Next &Replace &Remplacer Replace &All [All Types] [All Fields] Search text "{0}" not found Error - replacement failed Replaced {0} matches Sort Nodes What to Sort Que trie−t−on &Entire tree Arbre &Entier Selected &branches &Branches sélectionnées Selection's childre&n Les e&nfants de la sélection Selection's &siblings Les frères de la &sélection Sort Method Méthode de tri &Predefined Key Fields Node &Titles Sort Direction &Forward &Suivant &Reverse &Apply &Appliquer Update Node Numbering What to Update &Selection's children Root Node Noeud Racine Include top-level nodes Handling Nodes without Numbering Fields &Ignore and skip &Restart numbers for next siblings Reserve &numbers TreeLine Numbering No numbering fields were found in data types File Menu File Edit Menu Edit Node Menu Node Data Menu Data Tools Menu Tools View Menu View Window Menu Window Help Menu Help Keyboard Shortcuts Raccourcis clavier &Restore Defaults Key {0} is already used Clear &Key --Separator-- −Séparateur− Customize Toolbars Personnaliser les barres d''outils Toolbar &Size &Taille des barres d'outils Small Icons Petites icônes Large Icons Grandes icônes Toolbar Quantity Nombre de barres d'outls &Toolbars &Barre d'Outils A&vailable Commands Comma&ndes disponibles Tool&bar Commands Commandes des &barres d'outils Move &Up Déplacer vers le &haut Move &Down &Descendre Tree View Font Output View Font Editor View Font No menu TreeLine - Serious Error A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. Format Menu Format Customize Fonts &Use system default font App Default Font &Use app default font Externally Modified File &Overwrite File &Cancel Save File was externally modified at {} nodeformat Name Nom optiondefaults Monday Lundi Tuesday Mardi Wednesday Mercredi Thursday Jeudi Friday Vendredi Saturday Samedi Sunday Dimanche Startup Condition Au Démarrage Automatically open last file used Ouvrir automatiquement le dernier fichier utilisé Show descendants in output view Montrer descendants dans l'aperçu sortie Restore tree view states of recent files Restore previous window geometry Features Available Fonctionnalités disponibles Open files in new windows Ouverture des fichiers dans de nouvelles fenetres Click node to rename Rename new nodes when created Renommer les nouveaux noeuds quand ils sont créés Tree drag && drop available Glisser && déposer l'arborescence disponible dans le volet d'exploration Show icons in the tree view Afficher les icônes dans le volet d'exploration Show math fields in the Data Edit view Show numbering fields in the Data Edit view Undo Memory Mémoire utilisée pour la fonctionnalité "Annuler" Number of undo levels Nombre de niveaux d'annulation Auto Save Sauvegarde automatique Minutes between saves (set to 0 to disable) Recent Files Fichiers récents Number of recent files in the file menu Data Editor Formats Formats de l'Editeur de Données Times Heures Dates Dates First day of week Appearance Apparence Child indent offset (in font height units) Show breadcrumb ancestor view Show child pane in right hand views Remove inaccessible recent file entries Activate data editors on mouse hover Minimize application to system tray Indent (pretty print) TreeLine JSON files Limit data editor height to window size options Choose configuration file location User's home directory (recommended) Program directory (for portable use) &OK &OK &Cancel &Annuler printdata Error initializing printer Erreur à l'initialisation de l'imprimante TreeLine - Export PDF Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Warning: Page size setting unsupported on current printer. Save adjustment? Warning: Margin settings unsupported on current printer. Save adjustments? printdialogs Print Preview AperçuAvantImpression &Print... &Imprimer.... &General Options Options &Générales &Font Selection &Sélection Police &Header/Footer &En−tête/PiedDePage Print Pre&view... Aperçu a&vant impression... &OK &OK &Cancel &Annuler What to print Qu'imprimer  &Entire tree Arbre &Entier Selected &branches &Branches sélectionnées Selected &nodes &Nœuds sélectionnés Features Fonctionnalités &Include root node &Inclure le nœud racine &Keep first child with parent &Garder le premier enfant avec le parent Letter (8.5 x 11 in.) Lettre (8.5 × 11 pouces)  Legal (8.5 x 14 in.) Légal (8.5 × 14 pouces) Tabloid (11 x 17 in.) Tabloïde (11 × 17 pouces) A3 (279 x 420 mm) A3 (279 × 420 mm) A4 (210 x 297 mm) A4 (210 × 297 mm) A5 (148 x 210 mm) A5 (148 × 210 mm) Paper &Size &Taille papier Orientation Orientation &Units &Unités Columns Colonnes &Number of columns &Nombre de colonnes Default Font Police par défaut Select Font Sélectionner police &Font &Police Font st&yle St&yle de police Sample Exemple &Header Left &En-tête gauche Header C&enter En-tête C&entré Footer &Left Pied de page &Gauche Footer Ce&nter Pied de page Ce&ntré Fiel&ds Cham&ps Header and Footer En-tête et Pied de pages Extra Text Texte Supplémentaire &Prefix &Préfixe Format &Help Format de &l'Aide Fit Width Fit Page Zoom In Zoom Out Previous Page Next Page Single Page Facing Pages Print Setup Print Printing Setup Page &Setup Included Nodes Onl&y open node children &Draw lines to children Indent Indent Offse&t (line height units) Custom Size Inches (in) Millimeters (mm) Centimeters (cm) &Width: Height: Portra&it Lan&dscape Margins &Left: &Top: &Right: &Bottom: He&ader: Foot&er: Space between colu&mns &Use TreeLine output view font Si&ze AaBbCcDdEeFfGg...TtUuVvWvXxYyZz Header &Right Footer Righ&t Field For&mat Field Format for "{0}" Output &Format &Suffix Error: Page size or margins are invalid TreeLine PDF Printer Select &Printer recentfiles spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? Spell Check Error Erreur Correction Orthographe Locate aspell.exe, ipsell.exe or hunspell.exe Program (*.exe) Programme (*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed TreeLine Spell Check Vérification Orthographique TreeLIne Finished spell checking Spell Check Vérification orthographique Not in Dictionary Pas dans le dictionnaire Word: Mot: Context: Contexte: Suggestions Suggestions Ignor&e Ignor&er &Ignore All &Ignorer Tout &Add &Ajouter Add &Lowercase Ajouter &Minuscule &Replace &Remplacer Re&place All Rem&placer Tout &Cancel &Annuler Finished checking the branch Continue from the top? titlelistview Select in Tree treeformats DEFAULT DEFAUT FILE TYPE FIELD FieldType TitleFormat OutputFormat SpaceBetween FormatHtml Bullets Table ChildType Icon Icône GenericType ConditionalRule ListSeparator ChildTypeLimit Format Prefix Suffix InitialValue NumLines SortKeyNum SortForward EvalHtml treelocalcontrol Error - could not delete backup file {} Save changes to {}? Save changes? Enregistrer les changements? &Save &Enregistrer Save File Enregistrer Fichier Save the current file Save &As... Enregistrer &Sous... Save the file with a new name Enregistrer le fichier sous un nouveau nom &Export... &Exporter... Export the file in various other formats Prop&erties... Set file parameters like compression and encryption P&rint Setup... Set margins, page size and other printing options Print Pre&view... Aperçu a&vant impression... Show a preview of printing results Montrer l'aperçu de l'impression &Print... &Imprimer.... Print tree output based on current options Print &to PDF... Export to PDF with current printing options &Undo &Annuler Undo the previous action Annuler l'action précédente &Redo &Rétablir Redo the previous undo Rétablir l'annulation précédente Cu&t Co&uper Cut the branch or text to the clipboard Couper la branche ou le texte dans le presse-papier &Copy &Copier Copy the branch or text to the clipboard Copier la branche ou le texte dans le presse-papier &Paste C&oller Paste nodes or text from the clipboard Coller les noeuds ou le texte dans le presse-papier Paste non-formatted text from the clipboard &Bold Font Set the current or selected font to bold &Italic Font Set the current or selected font to italic U&nderline Font Set the current or selected font to underline &Font Size Set size of the current or selected text Small Default Large Larger Largest Set Font Size Font C&olor... Set the color of the current or selected text &External Link... Add or modify an extrnal web link Internal &Link... Add or modify an internal node link Clear For&matting Clear current or selected text formatting &Rename Rename the current tree entry title Insert Sibling &Before Insérer Frère A&vant Insert new sibling before selection Insérer le nouveau frère avant la sélection Insert Sibling &After Insérer Frère Apr&ès Insert new sibling after selection Insérer le nouveau frère après la sélection Add &Child Add new child to selected parent &Delete Node &Supprimer Noeud Delete the selected nodes Supprimer les noeuds sélectionnés &Indent Node Inden&ter Noeud Indent the selected nodes Indenter les noeuds sélectionnés &Unindent Node Unindent the selected nodes Désindenter les noeuds sélectionnés &Move Up &Déplacer En &haut Move the selected nodes up Déplacer les noeuds sélectionnés vers le haut M&ove Down D&éplacer En bas Move the selected nodes down Déplacer les noeuds sélectionnés vers le bas Move &First Déplacer &premier Move the selected nodes to be the first children Déplacer les nœuds sélectionnés comme premier enfant Move &Last Déplacer &dernier Move the selected nodes to be the last children Déplacer les nœuds sélectionnés comme dernier enfant &Set Node Type Set the node type for selected nodes Set Node Type Copy Types from &File... Copy the configuration from another TreeLine file Copier la configuration à partir d'un autre fichier TreeLine Flatten &by Category Collapse descendants by merging fields Add Category &Level... Insert category nodes above children Insérer les noeuds du classement au-dessus des fils &Spell Check... &New Window j&Nouvelle Fenetre Open a new window for the same file Error - could not write to {} TreeLine - Save As Error - could not write to file TreeLine - Open Configuration File Error - could not read file {0} Cannot expand without common fields Impossible de développer sans champs communs Category Fields Champ du Classement Select fields for new level Sélection des champs pour le nouveau niveau File saved Pa&ste Plain Text Paste C&hild Paste a child node from the clipboard Paste Sibling &Before Paste a sibling before selection Paste Sibling &After Paste a sibling after selection Paste Cl&oned Child Paste a child clone from the clipboard Paste Clo&ned Sibling Before Paste a sibling clone before selection Paste Clone&d Sibling After Paste a sibling clone after selection Clone All &Matched Nodes Convert all matching nodes into clones &Detach Clones Detach all cloned nodes in current branches S&wap Category Levels Swap child and grandchild category nodes Converted {0} branches into clones No identical nodes found Warning - file corruption! Skipped bad child references in the following nodes: Spell check the tree's text data &Regenerate References Force update of all conditional types & math fields Insert &Date Insert current date as text St&rikethrough Font Set the current or selected font to strikethough treemaincontrol Warning: Could not create local socket Error - could not write config file to {} Error - could not read file {0} Backup file "{}" exists. A previous session may have crashed &Restore Backup &Restaure Sauvegarde &Delete Backup &Supprime Sauvegarde &Cancel File Open &Annule Fichier Ouvert Error - could not rename "{0}" to "{1}" Error - could not remove backup file {} &New... &Nouveau… New File Nouveau Fichier Start a new file Commencer un nouveau fichier &Open... &Ouvir... Open File Ouvrir Fichier Open a file from disk Ouvrir un ficier à partir du disque Open Sa&mple... Ouvrir Exa&mple... Open Sample Open a sample file &Import... Open a non-TreeLine file &Quit &Quitter Exit the application Quitter l'application &Select All Select all text in an editor &Configure Data Types... &Paramètres du Type de Données... Modify data types, fields & output lines Modifier les types de données, les champs & les lignes en sortie Sor&t Nodes... Define node sort operations Update &Numbering... Update node numbering fields &Find Text... Find text in node titles & data &Conditional Find... Use field conditions to find nodes Find and &Replace... Replace text strings in node data &Text Filter... Filter nodes to only show text matches C&onditional Filter... Use field conditions to filter nodes &General Options... &Options Générales... Set user preferences for all files Configurer les préférences utilisateur pour tous les fichiers Set &Keyboard Shortcuts... Fixe les raccourcis &claviers... Customize keyboard commands Personnalise les commandes au clavier C&ustomize Toolbars... Customize toolbar buttons Personnalise les boutons des barres d'outils Customize Fo&nts... Customize fonts in various views &Basic Usage... Display basic usage instructions &Full Documentation... Open a TreeLine file with full documentation &About TreeLine... Display version info about this program &Select Template &Sélectionner un modèle TreeLine - Open File Open Sample File &Select Sample Conditional Find Conditional Filter Filtre conditionnel General Options Options Générales Error - basic help file not found TreeLine Basic Usage Error - documentation file not found Error - invalid TreeLine file {0} TreeLine version {0} written by {0} Library versions: missing directory Show C&onfiguration Structure... Show read-only visualization of type structure Custo&mize Colors... Customize GUI colors and themes treemodel treenode New Nouveau treestructure Main Base treeview Filtering by "{0}", found {1} nodes Conditional filtering, found {0} nodes Search for: Search for: {0} Search for: {0} (not found) Next: {0} Next: {0} (not found) treewindow Data Output Sortie des données Data Edit Title List Liste des titres &Expand Full Branch &Développer Toute la Branche Expand all children of the selected nodes &Collapse Full Branch &Réduire Toute la Branche Collapse all children of the selected nodes &Previous Selection Sélection &Précédente Return to the previous tree selection &Next Selection &Sélection suivante Go to the next tree selection in history Show Data &Output Montrer une &sortie des données Show data output in right view Afficher le volet de données dans la vue de droite Show Data &Editor Afficher l'&Editeur de Données Show data editor in right view Afficher l'éditeur de données dans la vue de droite Show &Title List Show title list in right view Afficher la liste des titres dans la vue de droite &Show Child Pane Toggle showing right-hand child views Toggle showing output view indented descendants &Close Window &Fermer la fenetre Close this window &File &Fichier &Edit &Editer &Node &Data &Données &Tools &Outils &View &Affichage &Window &Fenetre &Help A&ide Start Incremental Search Next Incremental Search Previous Incremental Search Show &Breadcrumb View Toggle showing breadcrumb ancestor view Show Output &Descendants Fo&rmat colorset Dialog background color Dialog text color Text widget background color Text widget foreground color Selected item background color Selected item text color Link text color Tool tip background color Tool tip foreground color Button background color Button text color Disabled text foreground color Disabled button text color Color Settings Color Theme Default system theme Dark theme Custom theme &OK &OK &Cancel &Annuler Custom Colors Theme Colors Select {0} color TreeLine-3.2.1/working/translations/treeline_it.ts000066400000000000000000005544431506556630100223260ustar00rootroot00000000000000 conditional starts with ends with contains True False and or [All Types] Node Type &Add New Rule &Remove Rule &OK &Cancel Find &Previous Find &Next &Filter &End Filter &Close No conditional matches were found Rule {0} Saved Rules Name: &Load &Save &Delete configdialog Configure Data Types T&ype List Typ&e Config Field &List &Field Config O&utput &Show Advanced &OK &Apply &Reset &Cancel &Hide Advanced Error - circular reference in math field equations Add or Remove Data Types &New Type... Co&py Type... Rena&me Type... &Delete Type Add Type Enter new type name: Copy Type &Derive from original Rename Type Rename from {} to: Cannot delete data type being used by nodes [None] no type set &Data Type Default Child &Type Icon Change &Icon Output Options Add &blank lines between nodes Allow &HTML rich text in format Add text bullet&s Use a table for field &data Combination && Child List Output &Separator Derived from &Generic Type Automatic Types None Modify Co&nditional Types Create Co&nditional Types Set Types Conditionally Modify &Field List Name Type Sort Key Move U&p Move Do&wn &New Field... Rena&me Field... Dele&te Field Sort &Keys... fwd rev Add Field Enter new field name: Rename Field File Info Reference F&ield &Field Type Outpu&t Format Format &Help Extra Text &Prefix Suffi&x Default &Value for New Nodes Editor Height Num&ber of text lines Math Equation Define Equation F&ield List &Title Format Out&put Format Other Field References Reference Le&vel Refere&nce Type The name cannot be empty The name must start with a letter The name cannot start with "xml" The name cannot contain spaces The following characters are not allowed: {} The name was already used Set Data Type Icon Clear &Select forward reverse Sort Key Fields Available &Fields &Sort Criteria Field Direction Move &Up &Move Down Flip &Direction Self Reference Parent Reference Root Reference Child Reference Child Count Date Result Time Result Boolean Result Text Result Arithmetic Operators Comparison Operators Text Operators add subtract multiply divide floor divide modulus power sum of items maximum minimum average absolute value square root natural logarithm base-10 logarithm factorial round to num digits lower integer higher integer truncated integer floating point sine of radians cosine of radians tangent of radians arc sine arc cosine arc tangent radians to degrees degrees to radians pi constant natural log constant equal to less than greater than less than or equal to greater than or equal to not equal to true value, condition, false value logical and logical or true if 1st text arg starts with 2nd arg true if 1st text arg ends with 2nd arg true if 1st text arg contains 2nd arg concatenate text join text using 1st arg as separator convert text to upper case convert text to lower case in 1st arg, replace 2nd arg with 3rd arg Define Math Field Equation Field References Reference &Level Reference &Type Available &Field List &Result Type Operations O&perator Type Oper&ator List Description &Equation Equation error: {} Output HTML Evaluate &HTML tags Child Type Limits [All Types Available] &Select All Select &None Number Result Count Number of Children dataeditors Today's &Date &Open Link Open &Folder External Link Scheme &Browse for File File Path Type Absolute Relative Address Display Name &OK &Cancel TreeLine - External Link File &Go to Target Internal Link &Open Picture Picture Link TreeLine - Picture File Set to &Now Clear &Link (Click link target in tree) link exports Bookmarks TreeLine - Export HTML TreeLine - Export Text Titles TreeLine - Export Plain Text TreeLine - Export Text Tables TreeLine - Export Generic XML TreeLine - Export TreeLine Subtree TreeLine - Export ODF Text TreeLine - Export HTML Bookmarks TreeLine - Export XBEL Bookmarks &HTML &Text &ODF Outline Book&marks &Single HTML page Single &HTML page with navigation pane Multiple HTML &pages with navigation pane Multiple HTML &data tables &Tabbed title text &Unformatted output of all text &HTML format bookmarks &XBEL format bookmarks File Export Choose export format type Choose export format subtype Choose export options What to Export &Entire tree Selected &branches Selected &nodes Other Options &Only open node children Include &print header && footer &Columns Navigation pane &levels Error - export template files not found. Check your TreeLine installation. Error - cannot link to unsaved TreeLine file. Save the file and retry. Warning - no relative path from "{0}" to "{1}". Continue with absolute path? Parent Tree&Line &XML (generic) Live tree view, linked to TreeLine file (for web server) Live tree view, single file (embedded data) &Comma delimited (CSV) table of descendants (level numbers) Comma &delimited (CSV) table of children (single level) Tab &delimited table of children (&single level) &Old TreeLine (2.0.x) &TreeLine Subtree &Include root nodes Must select nodes prior to export fieldformat Text HtmlText OneLineText SpacedText Number Math Numbering Boolean Date Time Choice AutoChoice Combination AutoCombination ExternalLink InternalLink Picture RegularExpression Now Optional Digit # Required Digit 0 Digit or Space (external) <space> Decimal Point . Decimal Comma , Space Separator (internal) <space> Optional Sign - Required Sign + Exponent (capital) E Exponent (small) e Number 1 Capital Letter A Small Letter a Capital Roman Numeral I Small Roman Numeral i Level Separator / Section Separator . "/" Character // "." Character .. Outline Example I../A../1../a)/i) Section Example 1.1.1.1 Separator / Example 1/2/3/4 yes/no true/false T/F Y/N Any Character . End of Text $ 0 Or More Repetitions * 1 Or More Repetitions + 0 Or 1 Repetitions ? Set of Numbers [0-9] Lower Case Letters [a-z] Upper Case Letters [A-Z] Not a Number [^0-9] Or | Escape a Special Character \ DateTime Day (1 or 2 digits) %-d Day (2 digits) %d Weekday Abbreviation %a Weekday Name %A Month (1 or 2 digits) %-m Month (2 digits) %m Month Abbreviation %b Month Name %B Year (2 digits) %y Year (4 digits) %Y Week Number (0 to 53) %-U Day of year (1 to 366) %-j Hour (0-23, 1 or 2 digits) %-H Hour (00-23, 2 digits) %H Hour (1-12, 1 or 2 digits) %-I Hour (01-12, 2 digits) %I Minute (1 or 2 digits) %-M Minute (2 digits) %M Second (1 or 2 digits) %-S Second (2 digits) %S Microseconds (6 digits) %f AM/PM %p Comma Separator \, Dot Separator \. DescendantCount genboolean true false yes no globalref TreeLine Files TreeLine Files - Compressed TreeLine Files - Encrypted All Files HTML Files Text Files XML Files ODF Text Files Treepad Files PDF Files CSV (Comma Delimited) Files All TreeLine Files Old TreeLine Files helpview Tools &Back &Forward &Home Find: Find &Previous Find &Next Text string not found imports &Tab indented text, one node per line Tab delimited text table with header &row Plain text &paragraphs (blank line delimited) Treepad &file (text nodes only) &Generic XML (non-TreeLine file) Open &Document (ODF) outline &HTML bookmarks (Mozilla Format) &XML bookmarks (XBEL format) FOLDER BOOKMARK SEPARATOR Link Text Import File Choose Import Method Invalid File "{0}" is not a valid TreeLine file. Use an import filter? TreeLine - Import File Error - could not read file {0} Error - improper format in {0} TABLE Bookmarks Too many entries on Line {0} Plain text, one &node per line (CR delimited) Bad CSV format on Line {0} Co&mma delimited (CSV) text table with level column && header row Comma delimited (CSV) text table &with header row Other Old Tree&Line File (1.x or 2.x) Invalid level number on line {0} Invalid level structure No headings found matheval Illegal "{}" characters Child references must be combined in a function Illegal syntax in equation Illegal function present: {0} Illegal object type or operator: {0} Invalid field modifiers miscdialogs &OK &Cancel Fields File Properties File Storage &Use file compression Use file &encryption Spell Check Language code or dictionary (optional) Math Fields &Treat blank fields as zeros Encrypted File Password Type Password for "{0}": Type Password: Re-Type Password: Remember password during this session Zero-length passwords are not permitted Re-typed password did not match Default - Single Line Text &Search Text What to Search Full &data &Titles only How to Search &Key words Key full &words F&ull phrase &Regular expression Find Find &Previous Find &Next Filter &Filter &End Filter &Close Error - invalid regular expression Search string "{0}" not found Find and Replace Replacement &Text Any &match Full &words Re&gular expression &Node Type N&ode Fields &Find Next &Replace Replace &All [All Types] [All Fields] Search text "{0}" not found Error - replacement failed Replaced {0} matches Sort Nodes What to Sort &Entire tree Selected &branches Selection's childre&n Selection's &siblings Sort Method &Predefined Key Fields Node &Titles Sort Direction &Forward &Reverse &Apply Update Node Numbering What to Update &Selection's children Root Node Include top-level nodes Handling Nodes without Numbering Fields &Ignore and skip &Restart numbers for next siblings Reserve &numbers TreeLine Numbering No numbering fields were found in data types File Menu File Edit Menu Edit Node Menu Node Data Menu Data Tools Menu Tools View Menu View Window Menu Window Help Menu Help Keyboard Shortcuts &Restore Defaults Key {0} is already used Clear &Key --Separator-- Customize Toolbars Toolbar &Size Small Icons Large Icons Toolbar Quantity &Toolbars A&vailable Commands Tool&bar Commands Move &Up Move &Down Tree View Font Output View Font Editor View Font No menu TreeLine - Serious Error A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. Format Menu Format Customize Fonts &Use system default font App Default Font &Use app default font Externally Modified File &Overwrite File &Cancel Save File was externally modified at {} nodeformat Name optiondefaults Monday Tuesday Wednesday Thursday Friday Saturday Sunday Startup Condition Automatically open last file used Show descendants in output view Restore tree view states of recent files Restore previous window geometry Features Available Open files in new windows Click node to rename Rename new nodes when created Tree drag && drop available Show icons in the tree view Show math fields in the Data Edit view Show numbering fields in the Data Edit view Undo Memory Number of undo levels Auto Save Minutes between saves (set to 0 to disable) Recent Files Number of recent files in the file menu Data Editor Formats Times Dates First day of week Appearance Child indent offset (in font height units) Show breadcrumb ancestor view Show child pane in right hand views Remove inaccessible recent file entries Activate data editors on mouse hover Minimize application to system tray Indent (pretty print) TreeLine JSON files Limit data editor height to window size options Choose configuration file location User's home directory (recommended) Program directory (for portable use) &OK &Cancel printdata Error initializing printer TreeLine - Export PDF Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Warning: Page size setting unsupported on current printer. Save adjustment? Warning: Margin settings unsupported on current printer. Save adjustments? printdialogs Print Preview Fit Width Fit Page Zoom In Zoom Out Previous Page Next Page Single Page Facing Pages Print Setup Print Printing Setup &General Options Page &Setup &Font Selection &Header/Footer Print Pre&view... &Print... &OK &Cancel What to print &Entire tree Selected &branches Selected &nodes Included Nodes &Include root node Onl&y open node children Features &Draw lines to children &Keep first child with parent Indent Indent Offse&t (line height units) Letter (8.5 x 11 in.) Legal (8.5 x 14 in.) Tabloid (11 x 17 in.) A3 (279 x 420 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) Custom Size Inches (in) Millimeters (mm) Centimeters (cm) &Units Paper &Size &Width: Height: Orientation Portra&it Lan&dscape Margins &Left: &Top: &Right: &Bottom: He&ader: Foot&er: Columns &Number of columns Space between colu&mns Default Font &Use TreeLine output view font Select Font &Font Font st&yle Si&ze Sample AaBbCcDdEeFfGg...TtUuVvWvXxYyZz &Header Left Header C&enter Header &Right Footer &Left Footer Ce&nter Footer Righ&t Fiel&ds Field For&mat Header and Footer Field Format for "{0}" Output &Format Format &Help Extra Text &Prefix &Suffix Error: Page size or margins are invalid TreeLine PDF Printer Select &Printer spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? Spell Check Error Locate aspell.exe, ipsell.exe or hunspell.exe Program (*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed TreeLine Spell Check Finished spell checking Spell Check Not in Dictionary Word: Context: Suggestions Ignor&e &Ignore All &Add Add &Lowercase &Replace Re&place All &Cancel Finished checking the branch Continue from the top? titlelistview Select in Tree treeformats DEFAULT FILE TYPE FIELD FieldType TitleFormat OutputFormat SpaceBetween FormatHtml Bullets Table ChildType Icon GenericType ConditionalRule ListSeparator ChildTypeLimit Format Prefix Suffix InitialValue NumLines SortKeyNum SortForward EvalHtml treelocalcontrol Error - could not delete backup file {} Save changes to {}? Save changes? &Save Save File Save the current file Save &As... Save the file with a new name &Export... Export the file in various other formats Prop&erties... Set file parameters like compression and encryption P&rint Setup... Set margins, page size and other printing options Print Pre&view... Show a preview of printing results &Print... Print tree output based on current options Print &to PDF... Export to PDF with current printing options &Undo Undo the previous action &Redo Redo the previous undo Cu&t Cut the branch or text to the clipboard &Copy Copy the branch or text to the clipboard &Paste Paste nodes or text from the clipboard Paste non-formatted text from the clipboard &Bold Font Set the current or selected font to bold &Italic Font Set the current or selected font to italic U&nderline Font Set the current or selected font to underline &Font Size Set size of the current or selected text Small Default Large Larger Largest Set Font Size Font C&olor... Set the color of the current or selected text &External Link... Add or modify an extrnal web link Internal &Link... Add or modify an internal node link Clear For&matting Clear current or selected text formatting &Rename Rename the current tree entry title Insert Sibling &Before Insert new sibling before selection Insert Sibling &After Insert new sibling after selection Add &Child Add new child to selected parent &Delete Node Delete the selected nodes &Indent Node Indent the selected nodes &Unindent Node Unindent the selected nodes &Move Up Move the selected nodes up M&ove Down Move the selected nodes down Move &First Move the selected nodes to be the first children Move &Last Move the selected nodes to be the last children &Set Node Type Set the node type for selected nodes Set Node Type Copy Types from &File... Copy the configuration from another TreeLine file Flatten &by Category Collapse descendants by merging fields Add Category &Level... Insert category nodes above children &Spell Check... &New Window Open a new window for the same file Error - could not write to {} File saved TreeLine - Save As Error - could not write to file TreeLine - Open Configuration File Error - could not read file {0} Cannot expand without common fields Category Fields Select fields for new level Pa&ste Plain Text Paste C&hild Paste a child node from the clipboard Paste Sibling &Before Paste a sibling before selection Paste Sibling &After Paste a sibling after selection Paste Cl&oned Child Paste a child clone from the clipboard Paste Clo&ned Sibling Before Paste a sibling clone before selection Paste Clone&d Sibling After Paste a sibling clone after selection Clone All &Matched Nodes Convert all matching nodes into clones &Detach Clones Detach all cloned nodes in current branches S&wap Category Levels Swap child and grandchild category nodes Converted {0} branches into clones No identical nodes found Warning - file corruption! Skipped bad child references in the following nodes: Spell check the tree's text data &Regenerate References Force update of all conditional types & math fields Insert &Date Insert current date as text St&rikethrough Font Set the current or selected font to strikethough treemaincontrol Warning: Could not create local socket Error - could not write config file to {} Error - could not read file {0} Backup file "{}" exists. A previous session may have crashed &Restore Backup &Delete Backup &Cancel File Open Error - could not rename "{0}" to "{1}" Error - could not remove backup file {} &New... New File Start a new file &Open... Open File Open a file from disk Open Sa&mple... Open Sample Open a sample file &Import... Open a non-TreeLine file &Quit Exit the application &Select All Select all text in an editor &Configure Data Types... Modify data types, fields & output lines Sor&t Nodes... Define node sort operations Update &Numbering... Update node numbering fields &Find Text... Find text in node titles & data &Conditional Find... Use field conditions to find nodes Find and &Replace... Replace text strings in node data &Text Filter... Filter nodes to only show text matches C&onditional Filter... Use field conditions to filter nodes &General Options... Set user preferences for all files Set &Keyboard Shortcuts... Customize keyboard commands C&ustomize Toolbars... Customize toolbar buttons Customize Fo&nts... Customize fonts in various views &Basic Usage... Display basic usage instructions &Full Documentation... Open a TreeLine file with full documentation &About TreeLine... Display version info about this program &Select Template TreeLine - Open File Open Sample File &Select Sample Conditional Find Conditional Filter General Options Error - basic help file not found TreeLine Basic Usage Error - documentation file not found Error - invalid TreeLine file {0} TreeLine version {0} written by {0} Library versions: missing directory Show C&onfiguration Structure... Show read-only visualization of type structure Custo&mize Colors... Customize GUI colors and themes treenode New treestructure Main treeview Filtering by "{0}", found {1} nodes Conditional filtering, found {0} nodes Search for: Search for: {0} Search for: {0} (not found) Next: {0} Next: {0} (not found) treewindow Data Output Data Edit Title List &Expand Full Branch Expand all children of the selected nodes &Collapse Full Branch Collapse all children of the selected nodes &Previous Selection Return to the previous tree selection &Next Selection Go to the next tree selection in history Show Data &Output Show data output in right view Show Data &Editor Show data editor in right view Show &Title List Show title list in right view &Show Child Pane Toggle showing right-hand child views Toggle showing output view indented descendants &Close Window Close this window &File &Edit &Node &Data &Tools &View &Window &Help Start Incremental Search Next Incremental Search Previous Incremental Search Show &Breadcrumb View Toggle showing breadcrumb ancestor view Show Output &Descendants Fo&rmat colorset Dialog background color Dialog text color Text widget background color Text widget foreground color Selected item background color Selected item text color Link text color Tool tip background color Tool tip foreground color Button background color Button text color Disabled text foreground color Disabled button text color Color Settings Color Theme Default system theme Dark theme Custom theme &OK &Cancel Custom Colors Theme Colors Select {0} color TreeLine-3.2.1/working/translations/treeline_pt.ts000066400000000000000000005675531506556630100223430ustar00rootroot00000000000000 conditional starts with começa com ends with acaba com contains contém True Verdadeiro False Falso and e or ou Node Type Tipo de ramo &Add New Rule Adicionar &Nova Regra &Remove Rule &Eliminar Regra &OK &OK &Cancel &Cancelar Find &Previous Encontrar &Anterior Find &Next Encontrar &Seguinte &Filter F&iltrar &End Filter &Terminar Filtragem &Close &Fechar No conditional matches were found Nenhum resultado satisfaz as condições Rule {0} Regra {0} [All Types] [Todos os Tipos] Saved Rules Name: &Load &Save &Guardar &Delete configdialog Configure Data Types Configurar Tipos de Dados T&ype List &Lista de Tipos Typ&e Config Configuração de &Tipos Field &List Lista de &Campos &Field Config C&onfiguração de Campos O&utput &Apresentação &Show Advanced &Mostrar Avançadas &OK &OK &Apply &Aplicar &Reset &Repor &Cancel &Cancelar &Hide Advanced &Ocultar Avançadas Error - circular reference in math field equations Erro - referência cíclica em equações de campos matemáticos Add or Remove Data Types Adicionar ou Remover Tipos de Dados &New Type... &Novo Tipo... Co&py Type... Co&piar Tipo... Rena&me Type... &Mudar o Nome... &Delete Type &Eliminar Tipo Add Type Adicionar Tipo Enter new type name: Introduza novo nome para o tipo: Copy Type Copiar Tipo &Derive from original &Derivadar de Original Rename Type Mudar Nome a Tipo Rename from {} to: Mudar nome de {} para: Cannot delete data type being used by nodes Não é possivel apagar tipo de dados em utilização por ramos [None] no type set [Nenhum] &Data Type Tipo de &Dados Default Child &Type Tipo de &descendente pré definido Icon Ícone Change &Icon Mudar &Ícone Output Options Opções de apresentação Add &blank lines between nodes Adicionar linhas &vazias entre ramos Allow &HTML rich text in format Permitir texto formatado em &HTML Add text bullet&s Adicionar &pontos de tópico Use a table for field &data &Utilizar uma tabela para dados dos campos Combination && Child List Output &Separator Carácter de &Separação de Combinações e Lista de Descendentes Derived from &Generic Type &Derivado de Tipo Genérico Automatic Types Tipos Automáticos None Nenhum Modify Co&nditional Types &Modificar Tipos Condicionais Create Co&nditional Types &Criar Tipos Condicionais Set Types Conditionally Definir tipos condicionalmente Modify &Field List &Modificar Lista de Campos Name Nome Type Tipo Sort Key Prioridade de Ordenamento Move U&p Mover para &cima Move Do&wn Mover para &Baixo &New Field... &Novo Campo... Rena&me Field... M&udar Nome... Dele&te Field &Eliminar Campo Sort &Keys... &Prioridade de Ordenamento... fwd Descendente rev Ascendente Add Field Adicionar Campo Enter new field name: Introduza o nome do novo campo: Rename Field Mudar Nome File Info Reference Informação sobre o ficheiro F&ield Ca&mpo &Field Type T&ipo de Campo Outpu&t Format &Formato de Apresentação Format &Help &Ajuda de Formato Extra Text Texto adicional &Prefix &Prefixo Suffi&x &Sufixo Default &Value for New Nodes Valor pré &definido para novos ramos Editor Height Altura da Caixa de Introdução Num&ber of text lines &Número de linhas de texto Math Equation Equação Matemática Define Equation Definir Equação F&ield List Li&sta de Campos &Title Format &Formatação do Título Out&put Format &Formatação de Apresentação Other Field References Referências a outros campo Reference Le&vel &Nível de Referência Refere&nce Type &Tipo de Referência The name cannot be empty O nome não pode ser vazio The name must start with a letter O nome deve começar com uma letra The name cannot start with "xml" O nome não pode começar com "xml" The name cannot contain spaces O nome não pode conter espaços The following characters are not allowed: {} Os seguintes carácteres não são permitidos: {} The name was already used Nome já em utilização Set Data Type Icon Definir Ícone do Tipo de Dados Clear &Select &Limpar Selecção forward Descendente reverse Ascendente Sort Key Fields Campos de Ordenamento Available &Fields Campos &Disponíveis &Sort Criteria &Critério de Ordenamento Field Campo Direction Direcção Move &Up Mover para &Cima &Move Down Mover para &Baixo Flip &Direction &Inverter Direcção Self Reference Auto Referência Parent Reference Referência a Ascendentes Child Reference Referência a Descendentes Child Count Número de Descendentes add adicionar subtract subtrair multiply multiplicar divide dividir floor divide Divisão arredondada modulus resto power potência sum of items sumatório maximum máximo minimum mínimo average média absolute value valor absoluto square root raiz quadrada natural logarithm logarítmo natural base-10 logarithm logarítmo de base 10 factorial factorial round to num digits arredondar para x dígitos lower integer inteiro inferior higher integer inteiro superior truncated integer inteiro truncado floating point ponto flutuante sine of radians seno de radianos cosine of radians coseno de radianos tangent of radians tangente de radianos arc sine arco seno arc cosine arco coseno arc tangent arco tangente radians to degrees radianos para graus degrees to radians graus para radianos pi constant constante pi natural log constant constante logarítmo natural Define Math Field Equation Definir equação do campo matemático Field References Referências a Campos Reference &Level &Nível de Referência Reference &Type &Tipo de Referência Description Descrição &Equation &Equação Equation error: {} Erro na equação: {} Root Reference Referência à Raiz Date Result Resultado de Data Time Result Resultado de Tempo Available &Field List Lista de &Campos Disponíveis &Result Type &Tipo de Resultados Boolean Result Resultado Boleano Text Result Resultado Textual Arithmetic Operators Operadores Aritméticos Comparison Operators Operadores de Comparação Text Operators Operadores de Texto equal to igual a less than menor que greater than maior que less than or equal to menor ou igual a greater than or equal to maior ou igual not equal to diferente de true value, condition, false value valor verdadeiro, condição, valor falso true if 1st text arg starts with 2nd arg verdadeiro se o 1º argumento de texto começar com o 2º argumento true if 1st text arg ends with 2nd arg verdadeiro se o 1º argumento de texto terminar com o 2º argumento true if 1st text arg contains 2nd arg verdadeiro se o 1º argumento de texto contiver o 2º argumento concatenate text concatenar texto join text using 1st arg as separator juntar texto utilizando o primeiro argumento como separador convert text to upper case converter texto para maiúsculas convert text to lower case converter texto para minúsculas in 1st arg, replace 2nd arg with 3rd arg no 1º argumento, substituir o 2º argumento pelo 3º argumento Operations Operações O&perator Type &Tipo de Operador Oper&ator List &Lista de Operadores logical and e lógico logical or ou lógico Output HTML Evaluate &HTML tags Child Type Limits [All Types Available] &Select All &Seleccionar Tudo Select &None Number Result Count Number of Children dataeditors Today's &Date Data de &Hoje &Open Link &Abrir Ligação External Link Ligação Externa Scheme Protocolo &Browse for File Procurar &Ficheiro File Path Type Tipo de Caminho para o Ficheiro Absolute Absoluto Relative Relativo Address Endereço Display Name Texto de Apresentação &OK &OK &Cancel &Cancelar TreeLine - External Link File TreeLine - Ligação para Ficheiro Externo &Go to Target &Ir para Destino Internal Link Ligação Interna &Open Picture &Abrir Imagem Picture Link Ligação para imagem TreeLine - Picture File TreeLine - Ficheiro de Imagem Open &Folder Abrir &Pasta Set to &Now Clear &Link (Click link target in tree) link dataeditview exports Bookmarks Favoritos TreeLine - Export HTML TreeLine - Exportar HTML TreeLine - Export Text Titles TreeLine - Exportar Texto de Títulos TreeLine - Export Plain Text TreeLine - Exportar Texto Simples TreeLine - Export Text Tables TreeLine - Exportar Tabelas de Texto TreeLine - Export Generic XML TreeLine - Exportar XML Genérico TreeLine - Export TreeLine Subtree TreeLine - Exportar Sub Árvore TreeLine TreeLine - Export ODF Text TreeLine - Exportar Texto ODF TreeLine - Export HTML Bookmarks TreeLine - Exportar Favoritos em HTML TreeLine - Export XBEL Bookmarks TreeLine - Exportar Favoritos em XBEL &HTML &HTML &Text &Texto &ODF Outline Índice &ODF Book&marks &Favoritos &Single HTML page HTML Página &Única Single &HTML page with navigation pane HTML página única com barra de &navegação Multiple HTML &pages with navigation pane &Multiplas páginas HTML com barra de navegação Multiple HTML &data tables Multiplas páginas HTML com &tabelas de informação &Tabbed title text &Títulos separados por tabulação &Unformatted output of all text Conteúdo não &formatado para todos os textos &HTML format bookmarks Favoritos em formato &HTML &XBEL format bookmarks Favoritos em formato &XBEL File Export Exportação de ficheiros Choose export format type Escolha o formato de exportação Choose export format subtype Escolha o subtipo do formato de exportação Choose export options Escolha as opções de exportação What to Export O que exportar &Entire tree Árvore &Inteira Selected &branches &Subramos Seleccionados Selected &nodes &Ramos Seleccionados Other Options Outras Opções &Only open node children &Apenas descendentes expandidos Include &print header && footer Incluir &cabeçalho e rodapé de impressão &Columns &Colunas Navigation pane &levels &Níveis da barra de navegação Error - export template files not found. Check your TreeLine installation. Error - cannot link to unsaved TreeLine file. Save the file and retry. Warning - no relative path from "{0}" to "{1}". Continue with absolute path? Parent Tree&Line &XML (generic) Live tree view, linked to TreeLine file (for web server) Live tree view, single file (embedded data) &Comma delimited (CSV) table of descendants (level numbers) Comma &delimited (CSV) table of children (single level) Tab &delimited table of children (&single level) &Old TreeLine (2.0.x) &TreeLine Subtree &Include root nodes Must select nodes prior to export fieldformat Text Texto HtmlText TextoHTML SpacedText TextoEspaçado Number Número Math Matemática Numbering Numeração Boolean Boleano Date Data Time Tempo Choice Escolha AutoChoice AutoEscolha Combination Combinação AutoCombination AutoCombinação ExternalLink LigaçãoExterna InternalLink LigaçãoInterna Picture Imagem RegularExpression ExpressãoRegular Now Agora Optional Digit # Dígito Opcional # Required Digit 0 Dígito Obrigatório 0 Digit or Space (external) <space> Dígito ou espaço (externo) <space> Decimal Point . Ponto Decimal . Decimal Comma , Vírgula Decimal , Space Separator (internal) <space> Espaço de Separação (interno) <space> Optional Sign - Sinal Opcional - Required Sign + Sinal Obrigatório + Exponent (capital) E Exponente (maiúscula) E Exponent (small) e Exponente (minúscula) e Number 1 Número 1 Capital Letter A Letra Maiúscula A Small Letter a Letra Minúscula a Capital Roman Numeral I Numeral Romano Maiúsculo I Small Roman Numeral i Numeral Romano Minúsculo i Level Separator / Separador de Nível / Section Separator . Separador de Secção . "/" Character // Carácter "/" // "." Character .. Carácter "." .. Outline Example I../A../1../a)/i) Exemplo de Índice I../A../1../a)/i) Section Example 1.1.1.1 Exemplo de Secção 1.1.1.1 Separator / Separador / Example 1/2/3/4 Exemplo 1/2/3/4 yes/no sim/não true/false verdadeiro/falso T/F V/F Y/N S/N Any Character . Qualquer carácter . End of Text $ Fim de texto $ 0 Or More Repetitions * 0 ou Mais Repetições * 1 Or More Repetitions + 1 Ou Mais Repetições + 0 Or 1 Repetitions ? 0 Ou 1 Repetições ? Set of Numbers [0-9] Conjunto de Números [0-9] Lower Case Letters [a-z] Letras Minúsculas [a-z] Upper Case Letters [A-Z] Letras Maiúsculas [A-Z] Not a Number [^0-9] Carácter não numérico [^0-9] Or | Ou | Escape a Special Character \ Terminar Carácter Especial \ OneLineText TextoLinhaUnica DateTime Day (1 or 2 digits) %-d Day (2 digits) %d Weekday Abbreviation %a Weekday Name %A Month (1 or 2 digits) %-m Month (2 digits) %m Month Abbreviation %b Month Name %B Year (2 digits) %y Year (4 digits) %Y Week Number (0 to 53) %-U Day of year (1 to 366) %-j Hour (0-23, 1 or 2 digits) %-H Hour (00-23, 2 digits) %H Hour (1-12, 1 or 2 digits) %-I Hour (01-12, 2 digits) %I Minute (1 or 2 digits) %-M Minute (2 digits) %M Second (1 or 2 digits) %-S Second (2 digits) %S Microseconds (6 digits) %f AM/PM %p Comma Separator \, Dot Separator \. DescendantCount genboolean true verdadeiro false falso yes sim no não globalref TreeLine Files Ficheiros TreeLine TreeLine Files - Compressed Ficheiros TreeLine - Comprimidos TreeLine Files - Encrypted Ficheiros TreeLine - Encriptados All Files Todos os Ficheiros HTML Files Ficheiros HTML Text Files Ficheiros de Texto XML Files Ficheiros XML ODF Text Files Ficheiros ODF Treepad Files Ficheiros Treepad PDF Files Ficheiros PDF CSV (Comma Delimited) Files All TreeLine Files Old TreeLine Files helpview Tools Ferramentas &Back &Retroceder &Forward &Avançar &Home &Início Find: Encontrar: Find &Previous Encontrar &Anterior Find &Next Encontrar &Seguinte Text string not found Texto não encontrado imports &Tab indented text, one node per line &Texto recuado por tabulação, um ramo por linha Tab delimited text table with header &row Tabela de texto delimitada por tabulação com &cabeçalhos e colunas Plain text &paragraphs (blank line delimited) &Parágrafos de texto simples (delimitados por linha em branco) Treepad &file (text nodes only) &Ficheiro Treepad (ramos de texto apenas) &Generic XML (non-TreeLine file) &XML Genérico (ficheiro não específico do TreeLine) Open &Document (ODF) outline Índice &Open Document (ODF) &HTML bookmarks (Mozilla Format) Favoritos em &HTML (Formato Mozilla) &XML bookmarks (XBEL format) &Favoritos XML (Formato XBEL) FOLDER PASTA BOOKMARK FAVORITO SEPARATOR SEPARADOR Link Ligação Text Texto Import File Importar Ficheiro Choose Import Method Escolher Método de Importação Invalid File Ficheiro Inválido "{0}" is not a valid TreeLine file. Use an import filter? "{0}" não é um ficheiro TreeLine válido. Utilizar um filtro de importação? TreeLine - Import File TreeLine - Importar Ficheiro Error - could not read file {0} Erro - não foi possível ler o ficheiro {0} Error - improper format in {0} Erro - formato de ficheiro impróprio {0} TABLE TABELA Bookmarks Favoritos Too many entries on Line {0} Plain text, one &node per line (CR delimited) Bad CSV format on Line {0} Co&mma delimited (CSV) text table with level column && header row Comma delimited (CSV) text table &with header row Other Old Tree&Line File (1.x or 2.x) Invalid level number on line {0} Invalid level structure No headings found matheval Illegal "{}" characters Carácteres "{0}" ilegais Child references must be combined in a function Referências a descendentes devem ser combinadas numa função Illegal syntax in equation Sintaxe ilegal na equação Illegal function present: {0} Função ilegal presente: {0} Illegal object type or operator: {0} Operador ou tipo de objecto ilegal: {0} Invalid field modifiers miscdialogs &OK &OK &Cancel &Cancelar Fields Campos File Properties Propriedades do Ficheiro File Storage Armazenamento do Ficheiro &Use file compression Utilizar &compressão de ficheiro Use file &encryption Utilizar &encriptação de ficheiro Spell Check Verificar Ortografia Language code or dictionary (optional) Código de linguagem ou dicionário (opcional) Math Fields Campos Matemáticos &Treat blank fields as zeros &Tratar campos vazios como zeros Encrypted File Password Palavra Passe de Ficheiro Encriptado Type Password for "{0}": Introduza a palavra passe para "{0}": Type Password: Introduza a Palavra Passe: Re-Type Password: Re-Introduza a Palavra Passe: Remember password during this session Lembrar a palavra passe durante esta sessão Zero-length passwords are not permitted Palavras passe vazias não são permitidas Re-typed password did not match Palavras passe introduzidas são diferentes Default - Single Line Text Pré definido - Texto em linha única &Search Text &Pesquisar Texto What to Search Onde pesquisar Full &data Toda a &informação &Titles only Apenas &Títulos How to Search Como pesquisar &Key words &Palavras chave parciais Key full &words Palavras chave &completas F&ull phrase &Frase completa &Regular expression &Expressão regular Find Encontrar Find &Previous Encontrar &Anterior Find &Next Encontrar &Seguinte Filter Filtrar &Filter &Filtrar &End Filter &Terminar Filtro &Close &Fechar Error - invalid regular expression Erro - Expressão Regular inválida Search string "{0}" not found Termos de pesquisa "{0}" não encontrados Find and Replace Encontrar e Substituir Replacement &Text Texto de &Substituição Any &match &Qualquer ocorrência Full &words Palavras &Completas Re&gular expression &Expressão regular &Node Type &Tipo de ramo N&ode Fields &Campos dos Ramos &Find Next Encontrar &Seguinte &Replace &Substituir Replace &All Substituir &Todos [All Types] [Todos os Tipos] [All Fields] [Todos os Campos] Search text "{0}" not found Termo de pesquisa "{0}" não encontrado Error - replacement failed Erro - substituição falhou Replaced {0} matches Foram substituidas {0} ocorrências Sort Nodes Ordenar Ramos What to Sort O que Ordenar &Entire tree &Toda a árvore Selected &branches Ramos &Seleccionados Selection's childre&n &Descendentes da selecção Selection's &siblings &Irmãos da selecção Sort Method Método de Ordenamento &Predefined Key Fields &Campos de ordenamento pré definidos Node &Titles Títulos dos &Ramos Sort Direction Direcção de Ordenamento &Forward &Ascendente &Reverse &Descendente &Apply &Aplicar Update Node Numbering Actualizar Numeração dos Ramos What to Update O que Actualizar &Selection's children &Descendentes da Selecção Root Node Raiz Include top-level nodes Icluir ramos dos níveis superiores Handling Nodes without Numbering Fields Critério para Ramos sem Campos de Numeração &Ignore and skip &Ignorar e saltar &Restart numbers for next siblings &Reiniciar contagem para próximos irmãos Reserve &numbers &Reservar números TreeLine Numbering Numeração TreeLine No numbering fields were found in data types Não foram encontrados campos de numeração nos tipos de dados File Menu Menu Ficheiro File Ficheiro Edit Menu Menu Editar Edit Editar Node Menu Menu Ramo Node Ramo Data Menu Menu Informação Data Informação Tools Menu Menu Ferramentas Tools Ferramentas View Menu Menu Ver View Ver Window Menu Menu Janela Window Janela Help Menu Menu Ajuda Help Ajuda Keyboard Shortcuts Atalhos de Teclado &Restore Defaults &Restaurar pré definições Key {0} is already used Tecla {0} já em utilização Clear &Key &Remover Atalho --Separator-- --Separador-- Customize Toolbars Personalizar Barra de Ferramentas Toolbar &Size &Tamanho da Barra de Ferramentas Small Icons Ícones Pequenos Large Icons Ícones Grandes Toolbar Quantity Número de Barras de Ferramentas &Toolbars &Barras de Ferramentas A&vailable Commands Comandos &Disponíveis Tool&bar Commands Comandos da &Barra de Ferramentas Move &Up Mover para &Cima Move &Down Mover para &Baixo Tree View Font Tipo de Letra da Árvore Output View Font Tipo de Letra de Apresentação Editor View Font Tipo de Letra da Vista de Edição No menu TreeLine - Serious Error A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. Format Menu Format Customize Fonts &Use system default font Utilizar fonte pré definida do &sistema App Default Font &Use app default font Externally Modified File &Overwrite File &Cancel Save File was externally modified at {} nodeformat Name Nome optiondefaults Monday Segunda-Feira Tuesday Terça-Feira Wednesday Quarta-Feira Thursday Quinta-Feira Friday Sexta-Feira Saturday Sábado Sunday Domingo Startup Condition Opções de Arranque Automatically open last file used Abrir automaticamente último ficheiro utilizado Show descendants in output view Mostrar descendentes na vista de apresentação Restore tree view states of recent files Restaurar o estado de visualização dos ficheiros recentes Restore previous window geometry Repor a anterior disposição de janelas Features Available Funcionalidades Disponíveis Open files in new windows Abrir ficheiros em novas janelas Click node to rename Clicar nos ramos para alterar nome Rename new nodes when created Editar nome de ramos após criação Tree drag && drop available Permitir arrastar e largar na vista da árvore Show icons in the tree view Mostrar ícones na vista em árvore Show math fields in the Data Edit view Mostrar campos matemáticos na Vista de Edição Show numbering fields in the Data Edit view Mostrar campos de numeração na Vista de Edição Undo Memory Memória de operações Number of undo levels Número de passos a desfazer Auto Save Gravação Automática Minutes between saves (set to 0 to disable) Minutos entre gravações (0 desactiva) Recent Files Ficheiros Recentes Number of recent files in the file menu Número de ficheiros recentes no menu ficheiro Data Editor Formats Formatos do Editor de Dados Times Tempo Dates Datas First day of week Primeiro dia da semana Appearance Aparência Child indent offset (in font height units) Recuo dos descendentes (em unidades de altura da fonte) Show breadcrumb ancestor view Show child pane in right hand views Remove inaccessible recent file entries Activate data editors on mouse hover Minimize application to system tray Indent (pretty print) TreeLine JSON files Limit data editor height to window size options Choose configuration file location Escolher localização do ficheiro de configuração User's home directory (recommended) Pasta do utilizador (recomendado) Program directory (for portable use) Pasta do programa (para utilização portátil) &OK &OK &Cancel &Cancelar printdata Error initializing printer Erro ao iniciar a impressora TreeLine - Export PDF TreeLine - Exportar PDF Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Warning: Page size setting unsupported on current printer. Save adjustment? Warning: Margin settings unsupported on current printer. Save adjustments? printdialogs Print Preview Previsualização de Impressão Fit Width Ajustar à Largura Fit Page Ajustar à Página Zoom In Aproximar Zoom Out Afastar Previous Page Página Anterior Next Page Página Seguinte Single Page Página única Facing Pages Páginas Consecutivas Print Setup Definições de Impressão Print Imprimir Printing Setup Opções de impressão &General Options &Opções Gerais Page &Setup Configuração de &Página &Font Selection Selecção de &Fonte &Header/Footer &Cabeçalho/Rodapé Print Pre&view... &Previsualização de Impressão... &Print... &Imprimir... &OK &OK &Cancel &Cancelar What to print O que imprimir &Entire tree &Árvore completa Selected &branches &Ramos e descendentes seleccionados Selected &nodes Ramos &Seleccioandos Included Nodes Ramos Incluídos &Include root node &Incluir Raiz Onl&y open node children Apenas descendentes de ramos &expandidos Features Opções &Draw lines to children &Desenhar linhas até descendentes &Keep first child with parent &Manter primeiro descendente com o ascendente Indent Avanço Indent Offse&t (line height units) &Distancia do Avanço (em unidades de altura de linha) Letter (8.5 x 11 in.) Carta (8.5 x 11 pol.) Legal (8.5 x 14 in.) Legal (8.5 x 14 pol.) Tabloid (11 x 17 in.) Tablóide (11 x 17 pol.) A3 (279 x 420 mm) A3 (279 x 420 mm) A4 (210 x 297 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A5 (148 x 210 mm) Custom Size Tamanho personalizado Inches (in) Polegadas (pol) Millimeters (mm) Milímetros (mm) Centimeters (cm) Centímetros (cm) &Units &Unidades Paper &Size &Tamanho do Papel &Width: &Largura: Height: Altura: Orientation Orientação Portra&it Ao &baixo Lan&dscape Ao &alto Margins Margens &Left: &Esquerda: &Top: &Topo: &Right: &Direita: &Bottom: &Base: He&ader: &Cabeçalho: Foot&er: &Rodapé: Columns Colunas &Number of columns &Número de colunas Space between colu&mns &Espaçamento entre colunas Default Font Fonte Pré Definida &Use TreeLine output view font Utilizar a fonte de apresentação do &TreeLine Select Font Seleccionar Fonte &Font &Fonte Font st&yle &Estilo de Fonte Si&ze &Tamanho Sample Amostra AaBbCcDdEeFfGg...TtUuVvWvXxYyZz AaBbCcDdEeFfGg...TtUuVvWvXxYyZz &Header Left &Esquerda do Cabeçalho Header C&enter &Centro do Cabeçalho Header &Right &Direita do Cabeçalho Footer &Left E&squerda do Rodapé Footer Ce&nter Ce&ntro do Rodapé Footer Righ&t Direi&ta do Rodapé Fiel&ds &Campos Field For&mat &Formato dos Campos Header and Footer Cabeçalho e Rodapé Field Format for "{0}" Formato de campo para "{0}" Output &Format Formato de &Apresentação Format &Help &Ajuda de Formato Extra Text Texto Extra &Prefix &Prefixo &Suffix &Sufixo Error: Page size or margins are invalid TreeLine PDF Printer Select &Printer recentfiles spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? Não foi possível encontrar aspell.exe, ispell.exe ou hunspell.exe Procurar localização? Spell Check Error Erro de Verificação Ortográfica Locate aspell.exe, ipsell.exe or hunspell.exe Localizar aspell.exe, ispell.exe ou hunspell.exe Program (*.exe) Programa (*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed Erro de verificação Ortográfica do TreeLine Cerifique-se que aspell, ispell ou hunspell estão instalados TreeLine Spell Check Verificação Ortográfica TreeLine Finished spell checking Terminada verificação ortográfica Spell Check Verificação Ortográfica Not in Dictionary Ausente no Dicionário Word: Palavra: Context: Contexto: Suggestions Sugestões Ignor&e &Ignorar &Ignore All Ignorar &Todas &Add &Adicionar Add &Lowercase Adicionar em &Minúsculas &Replace &Substituir Re&place All S&ubstituir Todas &Cancel &Cancelar Finished checking the branch Continue from the top? titlelistview Select in Tree treeformats DEFAULT PRÉ DEFINIDO FILE TYPE FIELD FieldType TitleFormat OutputFormat SpaceBetween FormatHtml Bullets Table ChildType Icon Ícone GenericType ConditionalRule ListSeparator ChildTypeLimit Format Prefix Suffix InitialValue NumLines SortKeyNum SortForward EvalHtml treelocalcontrol Error - could not delete backup file {} Erro - não foi possível apagar cópia de segurança {} Save changes to {}? Guardar alterações em {}? Save changes? Guardar alterações? &Save &Guardar Save File Guardar Ficheiro Save the current file Guardar o ficheiro actual Save &As... Guardar &Como... Save the file with a new name Guardar o ficheiro com um novo nome &Export... &Exportar... Export the file in various other formats Exportar o ficheiro em diversos outros formatos Prop&erties... &Propriedades... Set file parameters like compression and encryption Definir parâmetros do ficheiro como compressão e encriptação P&rint Setup... &Definições de Impressão... Set margins, page size and other printing options Definir margens, tamanho de papel e outras opções de impressão Print Pre&view... Pré &visualizar impressão... Show a preview of printing results Mostrar uma pré visualização do resultado da impressão &Print... &Imprimir... Print tree output based on current options Imprimir apresentação da árvore baseada nas opções actuais Print &to PDF... Imprimir para &PDF... Export to PDF with current printing options Exportar para PDF com as actuais opções de impressão &Undo &Desfazer Undo the previous action Reverte a última acção &Redo &Refazer Redo the previous undo Repõe a última acção desfeita Cu&t Cor&tar Cut the branch or text to the clipboard Cortar o ramo ou texto para a memória de trabalho &Copy &Copiar Copy the branch or text to the clipboard Copiar o ramo ou texto para a memória de trabalho &Paste C&olar Paste nodes or text from the clipboard Colar ramos ou texto da memória de trabalho Paste non-formatted text from the clipboard Colar texto sem formatação da memória de trabalho &Bold Font &Negrito Set the current or selected font to bold Definir o texto actual ou seleccionado como negrito &Italic Font &Itálico Set the current or selected font to italic Definir o texto actual ou seleccionado como itálico U&nderline Font &Sublinhado Set the current or selected font to underline Definir o texto actual ou seleccionado como sublinhado &Font Size &Tamanho do texto Set size of the current or selected text Definir o tamanho do texto actual ou seleccionado Small Pequeno Default Normal Large Grande Larger Maior Largest Muito Grande Set Font Size Definir tamanho do texto Font C&olor... Co&r do Texto... Set the color of the current or selected text Definir a cor do texto actual ou seleccionado &External Link... &Ligação Externa... Add or modify an extrnal web link Adicionar ou modificar uma ligação externa para a internet Internal &Link... Ligação &Interna... Add or modify an internal node link Adicionar ou modificar uma ligação interna para outro ramo Clear current or selected text formatting Remover a formatação do texto actual ou seleccionado &Rename &Mudar Nome Rename the current tree entry title Alterar o nome da entrada actual na árvore Insert Sibling &Before Inserir Irmão &Antes Insert new sibling before selection Inserir novo ramo acima da selecção Insert Sibling &After Inserir Irmão &Depois Insert new sibling after selection Inserir novo ramo abaixo da selecção Add &Child Adicionar De&scendente Add new child to selected parent Adicionar sub ramo ao ramo seleccionado &Delete Node &Eliminar Ramo Delete the selected nodes Eliminar os ramos seleccionados &Indent Node &Recuar Ramo Indent the selected nodes Avançar os ramos seleccionados &Unindent Node A&vançar Ramo Unindent the selected nodes Recuar os ramos seleccionados &Move Up Mover para &Cima Move the selected nodes up Mover para cima os ramos seleccionados M&ove Down Mover para &Baixo Move the selected nodes down Mover para baixo os ramos seleccionados Move &First Colocar em &Primeiro Move the selected nodes to be the first children Mover os ramos seleccionados para que sejam os primeiros descendentes Move &Last Colocar em &Último Move the selected nodes to be the last children Mover os ramos seleccionados para que sejam os últimos descendentes &Set Node Type Definir &Tipo de Ramo Set the node type for selected nodes Definir o tipo de dados para os ramos seleccionados Set Node Type Definir Tipo de Ramo Copy Types from &File... Copiar Tipos de Outro &Ficheiro... Copy the configuration from another TreeLine file Copiar configuração de outro ficheiro TreeLine Flatten &by Category &Nivelar por categoria Collapse descendants by merging fields Colapsar descendentes juntando campos Add Category &Level... &Adicionar Nível por Categoria... Insert category nodes above children Insere ramos sobre descendentes classificanado segundo um campo &Spell Check... &Verificar Ortografia... &New Window &Nova Janela Open a new window for the same file Abrir nova vista do mesmo ficheiro Error - could not write to {} Erro - não é possível escrever para {} TreeLine - Save As TreeLine - Guardar Como Error - could not write to file Erro - não foi possível escrever para o ficheiro TreeLine - Open Configuration File TreeLine - Abrir Ficheiro de Configuração Error - could not read file {0} Erro - não foi possível ler o ficheiro {0} Cannot expand without common fields Não é possível expandir sem campos em comum Category Fields Campos de Categorias Select fields for new level Seleccione campo para novo nível Clear For&matting Limpar &Formatação File saved Ficheiro gravado Pa&ste Plain Text Paste C&hild Paste a child node from the clipboard Paste Sibling &Before Paste a sibling before selection Paste Sibling &After Paste a sibling after selection Paste Cl&oned Child Paste a child clone from the clipboard Paste Clo&ned Sibling Before Paste a sibling clone before selection Paste Clone&d Sibling After Paste a sibling clone after selection Clone All &Matched Nodes Convert all matching nodes into clones &Detach Clones Detach all cloned nodes in current branches S&wap Category Levels Swap child and grandchild category nodes Converted {0} branches into clones No identical nodes found Warning - file corruption! Skipped bad child references in the following nodes: Spell check the tree's text data &Regenerate References Force update of all conditional types & math fields Insert &Date Insert current date as text St&rikethrough Font Set the current or selected font to strikethough treemaincontrol Warning: Could not create local socket Aviso: Não foi possível criar ligação local Error - could not write config file to {} Erro - não foi possível gravar configuração no ficheiro {0} Error - could not read file {0} Erro - não foi possível ler o ficheiro {0} Backup file "{}" exists. A previous session may have crashed Cópia de segurança {0} existente. Uma sessão anterior pode ter terminado inesperadamente &Restore Backup &Restaurar Cópia de Segurança &Delete Backup &Apagar Cópia de Segurança &Cancel File Open &Cancelar Abertura de Ficheiro Error - could not rename "{0}" to "{1}" Erro - não foi possível alterar o nome de "{0}" para"{1}" Error - could not remove backup file {} Erro - não foi possível remover a cópia de segurança {} &New... &Novo... New File Novo Ficheiro Start a new file Criar um novo ficheiro &Open... &Abrir... Open File Abrir um Ficheiro Open a file from disk Abrir um ficheiro do disco Open Sa&mple... A&brir Exemplo... Open Sample Abrir um Exemplo Open a sample file Abrir um ficheiro de exemplo &Import... &Importar... Open a non-TreeLine file Abrir um ficheiro alheio ao TreeLine &Quit &Sair Exit the application Sair da aplicação &Configure Data Types... &Configurar Tipos de Dados... Modify data types, fields & output lines Modificar tipos de dados, campos e opções de apresentação Sor&t Nodes... &Ordenar Ramos... Define node sort operations Definir operações de ordenamento Update &Numbering... &Actualizar Numeração... Update node numbering fields Actualizar os campos de numeração &Find Text... &Encontrar Texto... Find text in node titles & data Encontrar texto nos títulos e conteúdo dos ramos &Conditional Find... &Procura Condicional... Use field conditions to find nodes Utilizar condições para encontrar ramos Find and &Replace... Encontar e &Substituir... Replace text strings in node data Substituir texto no conteúdo dos ramos &Text Filter... Filtro de &Texto... Filter nodes to only show text matches Filtrar ramos para mostrar apenas textos correspondentes C&onditional Filter... Filtro &Condicional... Use field conditions to filter nodes Utilizar condições para filtrar ramos &General Options... &Opções Gerais... Set user preferences for all files Definir opções do utilizador para todos os ficheiros Set &Keyboard Shortcuts... Definir &Atalhos de Teclado... Customize keyboard commands Personalizar comandos de teclado C&ustomize Toolbars... Personalizar &Barras de Ferramentas... Customize toolbar buttons Personalizar os botões das barras de ferramentas Customize Fo&nts... Personalizar &Fontes... Customize fonts in various views Personalizar as fontes utilizadas nas diversas vistas &Basic Usage... Utilização &Básica... Display basic usage instructions Mostrar instruções de utilização básica &Full Documentation... &Documentação Completa... Open a TreeLine file with full documentation Abrir um ficheiro TreeLine com a documentação completa &About TreeLine... &Acerca do TreeLine... Display version info about this program Mostrar informção sobre a versão deste programa &Select Template Seleccionar &Modelo TreeLine - Open File TreeLine -Abrir Ficheiro Open Sample File Abrir Ficheiro de Exemplo &Select Sample &Seleccione um exemplo Conditional Find Procura Condicional Conditional Filter Filtro Condicional General Options Opções Gerais Error - basic help file not found Erro -Ficheiro de ajuda básica não encontrado TreeLine Basic Usage Utilização Básica TreeLine Error - documentation file not found Erro - Ficheiro de documentação não encontrado &Select All &Seleccionar Tudo Select all text in an editor Seleccionar todo o texto num editor Error - invalid TreeLine file {0} TreeLine version {0} written by {0} Library versions: missing directory Show C&onfiguration Structure... Show read-only visualization of type structure Custo&mize Colors... Customize GUI colors and themes treemodel treenode New Novo treeopener treestructure Main Principal treeview Filtering by "{0}", found {1} nodes Filtragem por "{0}", encontrados {1} ramos Conditional filtering, found {0} nodes Filtragem condicional, encontrados {0} ramos Search for: Search for: {0} Search for: {0} (not found) Next: {0} Next: {0} (not found) treewindow Data Output Apresentação de Informação Data Edit Edição de Informação Title List Lista de Títulos &Expand Full Branch &Expandir Ramo Completo Expand all children of the selected nodes Expandir todos os descendentes dos ramos seleccionados &Collapse Full Branch &Colapsar Ramo Completo Collapse all children of the selected nodes Colapsar todos os descendentos dos ramos seleccionados &Previous Selection Selecção &Anterior Return to the previous tree selection Repor a anterior selecção da árvore &Next Selection Selecção &Seguinte Go to the next tree selection in history Ir para a selecção da árvore seguinte no histórico Show Data &Output M&ostrar Apresentação de Informação Show data output in right view Mostrar Apresentação de Dados na vista direita Show Data &Editor Mostrar Editor de &Informação Show data editor in right view Mostrar o editor de informação na vista direita Show &Title List Mostrar &Lista de Títulos Show title list in right view Mostra lista de títulos na vista direita &Show Child Pane Mostrar Painel dos &Descendentes Toggle showing right-hand child views Alternar mostrar vista de descendentes na vista direita Toggle showing output view indented descendants Alternar mostrar a apresentação de descendentes &Close Window &Fechar Janela Close this window Fechar esta janela &File &Ficheiro &Edit &Editar &Node &Ramo &Data &Informação &Tools Fe&rramentas &View &Ver &Window &Janela &Help &Ajuda Start Incremental Search Next Incremental Search Previous Incremental Search Show &Breadcrumb View Toggle showing breadcrumb ancestor view Show Output &Descendants Fo&rmat colorset Dialog background color Dialog text color Text widget background color Text widget foreground color Selected item background color Selected item text color Link text color Tool tip background color Tool tip foreground color Button background color Button text color Disabled text foreground color Disabled button text color Color Settings Color Theme Default system theme Dark theme Custom theme &OK &OK &Cancel &Cancelar Custom Colors Theme Colors Select {0} color TreeLine-3.2.1/working/translations/treeline_ru.ts000066400000000000000000006445321506556630100223370ustar00rootroot00000000000000 genboolean true истина false ложь no нет yes да conditional starts with начинается с True Истина False Ложь contains содержит ends with оканчивается на or или and и [All Types] [Все Типы] Node Type Тип Узла &Add New Rule &Добавить Новое Правило &Remove Rule &Удалить Правило &OK &OK &Cancel &Отмена Saved Rules Сохраненные Правила Name: Имя: &Load &Загрузить &Save &Сохранить &Delete &Удалить Find &Previous Найти &Предыдущий Find &Next Найти &Следующий &Filter От&фильтровать &End Filter Прекратить &Фильтрацию &Close &Закрыть No conditional matches were found Удовлетворяющие условию совпадения не найдены Rule {0} Правило {0} colorset Dialog background color Цвет фона интерфейса Dialog text color Цвет шрифта интерфейса Text widget background color Цвет фона элементов интерфейса Text widget foreground color Цвет фона символов элементов интерфейса Selected item background color Цвет фона выбранного пункта меню Selected item text color Цвет шрифта выбранного пункта меню Link text color Цвет шрифта гиперссылки Tool tip background color Цвет фона всплывающей подсказки Tool tip foreground color Цвет фона символов всплывающей подсказки Button background color Цвет фона кнопки Button text color Цвет шрифта кнопки Disabled text foreground color Цвет шрифта неактивного текста Disabled button text color Цвет шрифта неактивной кнопки Color Settings Настройка Цветов Color Theme Цветовая Тема Default system theme Тема системы по умолчанию Dark theme Темная тема Custom theme Тема пользователя &OK &OK &Cancel &Отмена Custom Colors Цвета Пользователя Theme Colors Цвета Темы Select {0} color Вабрать {0} цвет configdialog [None] [Ни один] Configure Data Types Настройка Типов Данных T&ype List Список &Типов Typ&e Config Настройка &Типа Field &List Список &Полей &Field Config Настройка &Поля O&utput &Вывод &Show Advanced Показать &Дополнительные Настройки &OK &OK &Apply &Применить &Reset &Сбросить &Cancel &Отмена &Hide Advanced &Скрыть Дополнительные Настройки Error - circular reference in math field equations Ошибка — циклическая ссылка в выражениях математического поля Add or Remove Data Types Добавить или Удалить Типы Данных &New Type... &Новый Тип... Co&py Type... С&копировать Тип... Rena&me Type... &Переименовать Тип... &Delete Type &Удалить Тип Add Type Добавить Тип Enter new type name: Введите имя нового типа: Copy Type Копировать Тип &Derive from original Наследовать от &источника Rename Type Переименовать Тип Rename from {} to: Переименовать из {} в: Cannot delete data type being used by nodes Невозможно удалить тип, в узлах которого содержатся данные [None] тип не задан [Ни один] &Data Type Тип &Данных Default Child &Type Тип &Дочернего Узла по Умолчанию Icon Значок Change &Icon Сменить &Значок Output Options Опции Вывода Add &blank lines between nodes Добавить &пустые строки между узлами Allow &HTML rich text in format Учитывать при форматировании &HTML-разметку Add text bullet&s Добавить &маркеры текста Use a table for field &data Использовать таблицу для &данных поля Combination && Child List Output &Separator &Разделитель Значений Типа Комбинация && Списков Дочерних Узлов Derived from &Generic Type Сделать Производным от &Общего Типа Automatic Types Автоматические Типы Child Type Limits Ограничения Типа Дочернего Узла None Ни один Modify Co&nditional Types Изменить &Условные Типы Create Co&nditional Types Создать У&словные Типы Set Types Conditionally Назначить Типы в зависимости от Условий Modify &Field List Изменить Список &Полей Name Имя Type Тип Sort Key Ключ Сортировки Move U&p Переместить В&верх Move Do&wn Переместить В&низ &New Field... &Новое Поле... Rena&me Field... Пе&реименовать Поле... Dele&te Field &Удалить Поле Sort &Keys... Ключи &Сортировки... fwd >> rev << Enter new field name: Введите имя нового поля: Add Field Добавить Поле Rename Field Переименовать Поле File Info Reference Ссылка на Информацию о Файле F&ield &Поле &Field Type Тип &Поля Outpu&t Format Формат &Вывода Format &Help Справка по &Форматированию Extra Text Дополнительный Текст &Prefix &Приставка Suffi&x &Окончание Default &Value for New Nodes Значение по &Умолчанию для Новых Узлов Editor Height Высота Поля Редактора Num&ber of text lines &Число строк текста Math Equation Математическое Выражение Define Equation Задать Выражение Output HTML Вывод в HTML Evaluate &HTML tags Определять теги &HTML F&ield List Список &Полей &Title Format Формат &Заголовка Out&put Format Формат &Вывода Other Field References Ссылки на Другие Поля Reference Le&vel &Уровень Ссылки Refere&nce Type Тип &Ссылки [All Types Available] [Все Типы Допустимы] &Select All Выбрать &Все Select &None Не Выбрать &Ничего The name cannot be empty Имя не может быть пустым The name must start with a letter Имя должно начинаться с буквы The name cannot start with "xml" Имя не может начинаться с "xml" The name cannot contain spaces Имя не может содержать пробелы The following characters are not allowed: {} Следующие символы недопустимы: {} The name was already used Имя уже использовано Set Data Type Icon Назначить Значок Типа Данных Clear &Select Очистить &Выбор reverse сменить направление на обратное forward вперед Sort Key Fields Поля Ключа Сортировки Available &Fields Допустимые &Поля &Sort Criteria Критерии &Сортировки Field Поле Direction Направление Move &Up Переместить &Вверх &Move Down Переместить В&низ Flip &Direction Сменить &Направление Parent Reference Ссылка на Поля Родительского Узла Self Reference Ссылка на Поля Своего Узла Child Count Число Подсчитанных Дочерних Узлов Root Reference Ссылка на Поле Корневого Узла Child Reference Ссылка на Поле Дочернего Узла Number Result Итоговое Число Date Result Итоговая Дата Time Result Итоговое Время Boolean Result Итоговое Значение Логического Типа Text Result Итоговый Текст Comparison Operators Операторы Сравнения Arithmetic Operators Арифметические Операторы Text Operators Текстовые Операторы add сложить subtract вычесть multiply умножить divide разделить floor divide целочисленное деление modulus модуль power возвести в степень sum of items сумма элементов maximum максимум minimum минимум average среднее absolute value абсолютное значение square root квадратный корень natural logarithm натуральный логарифм base-10 logarithm десятичный логарифм factorial факториал round to num digits округлить до числа разрядов lower integer меньшее целое число higher integer большее целое число truncated integer усеченное целое число floating point плавающая точка sine of radians синус в радианах cosine of radians косинус в радианах tangent of radians тангенс в радианах arc sine арксинус arc cosine арккосинус arc tangent арктангенс radians to degrees радианы в градусы degrees to radians градусы в радианы pi constant число пи natural log constant основание натурального логарифма equal to равно less than меньше чем greater than больше чем less than or equal to меньше или равно greater than or equal to больше или равно not equal to не равно true value, condition, false value истинное значение, условие, ложное значение logical and логическое И logical or логическое ИЛИ true if 1st text arg starts with 2nd arg истина, если 1-й аргумент начинается со 2-го аргумента true if 1st text arg ends with 2nd arg истина, если 1-й текстовый аргумент оканчивается 2-м аргументом true if 1st text arg contains 2nd arg истина, если 1-й текстовый аргумент содержит 2-й аргумент concatenate text сцепить текстовые строки join text using 1st arg as separator присоединить текст, используя значение 1-го аргумента в качестве разделителя convert text to upper case преобразовать текст в верхний регистр convert text to lower case преобразовать текст в нижний регистр in 1st arg, replace 2nd arg with 3rd arg заменить в 1-м аргументе 2-й аргумент 3-м аргументом Define Math Field Equation Задать Выражение Математического Поля Field References Ссылки на Поле Reference &Level &Уровень Ссылки Reference &Type &Тип Ссылки Available &Field List Список Допустимых &Полей &Result Type &Тип Результата Operations Операции O&perator Type Тип &Оператора Oper&ator List Список &Операторов Description Описание &Equation &Выражение Count Подсчитать Number of Children Число Дочерних Узлов Equation error: {} Ошибка в выражении: {} [None] no type set dataeditors Today's &Date Сегодняшняя &Дата Set to &Now Установить &Сегодняшнюю Дату &Open Link &Открыть Гиперссылку Open &Folder Открыть &Папку External Link Внешняя Гиперссылка Scheme Структура &Browse for File &Поиск Файла File Path Type Задать Тип Пути к Файлу Absolute Абсолютный Relative Относительный Address Адрес Display Name Показать Имя TreeLine - External Link File TreeLine — Гиперссылка на Внешний Файл &Go to Target &Перейти к Цели Clear &Link Очистить &Гиперссылку (Click link target in tree) Кликните на целевую гиперссылку в дереве Internal Link Внутренняя Гиперссылка &OK &OK &Cancel &Отмена link гиперссылка &Open Picture &Открыть Изображение Picture Link Гиперссылка на Изображение TreeLine - Picture File TreeLine — Файл с Изображением miscdialogs &OK &OK &Cancel &Отмена Fields Поля File Properties Свойства Файла File Storage Файловое Хранилище &Use file compression Применить с&жатие файлов Use file &encryption Применить &шифрование файлов Spell Check Проверка Правописания Language code or dictionary (optional) Код языка или словарь (по желанию) Math Fields Математические Поля &Treat blank fields as zeros &Обрабатывать пустые поля как нули Encrypted File Password Пароль к Зашифрованному Файлу Type Password for "{0}": Введите Пароль для "{0}": Type Password: Введите Пароль: Re-Type Password: Введите Пароль Заново: Remember password during this session Запомнить пароль текущей сессии Zero-length passwords are not permitted Пароли нулевой длины не допустимы Re-typed password did not match Вновь набранный пароль не подходит Default - Single Line Text По Умолчанию — Однострочный Текст TreeLine - Serious Error TreeLine — Серьезная Ошибка A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. Возникла серьезная ошибка. TreeLine может находиться в нестабильном состоянии. Рекомендуется сохранить файл с внесенными изменениями под другим именем и перезапустить TreeLine. Отладочную информацию, приведенную ниже, Вы можете скопировать и отправить электронной почтой на e-mail: doug101@bellz.org с описанием обстоятельств возникновения ошибки. &Close &Закрыть &Search Text &Искомый Текст What to Search В Чем Искать Full &data Во всех &данных &Titles only Только в &заголовках How to Search Как Искать &Key words &Ключевые слова Key full &words Полные ключевые &слова F&ull phrase Полное &выражение &Regular expression &Регулярное выражение Find Поиск Find &Next Найти &Следующий Filter Фильтровать &Filter &Фильтровать &End Filter &Прекратить Фильтрацию Search string "{0}" not found Искомая строка "{0}" не найдена Find and Replace Поиск и Замена Replacement &Text Заменяющий &Текст Any &match Любое &совпадение Full &words Целые &слова Re&gular expression Ре&гулярное выражение &Node Type Тип &Узла N&ode Fields Поля &Узлов Find &Previous Найти &Предыдущий &Find Next Найти &Следующий &Replace &Заменить Replace &All Заменить &Все [All Types] [Все Типы] [All Fields] [Все Поля] Error - invalid regular expression Ошибка — неверное регулярное выражение Search text "{0}" not found Искомый текст "{0}" не найден Error - replacement failed Ошибка — замена невозможна Replaced {0} matches Заменено {0} совпадений Sort Nodes СортироватьУзлы What to Sort Что Сортировать &Entire tree Все &дерево Selected &branches Выбранные &ветви Selection's childre&n &Дочерние узлы в выбранном Selection's &siblings &Сестринские узлы в выбранном Sort Method Способ Сортировки &Predefined Key Fields &Предопределенные Ключевые Поля Node &Titles &Заголовки Узлов Sort Direction Направление Сортировки &Forward &Вперед &Reverse &Сменить направление &Apply &Применить Update Node Numbering Обновить Нумерацию Узлов What to Update Что Обновлять &Selection's children &Дочерние узлы в выбранном Root Node Корневой Узел Include top-level nodes Включить узлы верхних уровней Handling Nodes without Numbering Fields Обработка Узлов без Полей Нумерации &Ignore and skip &Игнорировать и пропустить &Restart numbers for next siblings &Перезапустить нумерацию с начала для следующих сестринских узлов Reserve &numbers За&резервировать номера TreeLine Numbering Нумерация TreeLine No numbering fields were found in data types Поля нумерации в типах данных не найдены File Файл File Menu Меню Файл Edit Редактировать Edit Menu Меню Правка Node Узел Node Menu Меню Узел Data Данные Data Menu Меню Данные Tools Инструменты Tools Menu Меню Инструменты Format Форматировать Format Menu Меню Формат View Вид View Menu Меню Вид Window Окно Window Menu Меню Окно Help Справка Help Menu Меню Справки Keyboard Shortcuts Горячие Клавиши No menu Меню отсутствует &Restore Defaults Восстановить Значения по &Умолчанию Key {0} is already used Ключ {0} уже используется Clear &Key Очистить &Ключ --Separator-- --Разделитель-- Customize Toolbars Настроить Панели Инструментов Toolbar &Size &Размер Панели Инструментов Large Icons Большие Значки Small Icons Маленькие Значки Toolbar Quantity Количество Панелей Инструментов &Toolbars &Панели Инструментов A&vailable Commands До&пустимые Команды Tool&bar Commands Команды &Панели Инструментов Move &Up Переместить &Вверх Move &Down Переместить &Вниз Customize Fonts Настроить Шрифты &Use system default font Использовать &системный шрифт по умолчанию App Default Font Шрифт Приложения по Умолчанию &Use app default font &Использовать шрифт приложения по умолчанию Tree View Font Шифт для Просмотра Дерева Output View Font Шрифт в Форме Вывода Editor View Font Шрифт Редактора Language code or dictionary (optional) Externally Modified File &Overwrite File &Cancel Save A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. File was externally modified at {} options Choose configuration file location Выберите расположение файла конфигурации User's home directory (recommended) Домашняя директория пользователя (рекомендуется) Program directory (for portable use) Директория программы (для портативного использования) &OK &OK &Cancel &Отмена printdialogs Print Preview Предварительный Просмотр Печати Fit Width Заполнить по Ширине Fit Page Страница Целиком Zoom In Увеличить Zoom Out Уменьшить Previous Page Предыдущая Страница Next Page Следующая Страница Single Page Одниночная Страница Facing Pages Страницы в Развороте Print Setup Настройка Печати Print Печать Printing Setup Настройка Печати &General Options &Общие Настройки Page &Setup &Параметры Страницы &Font Selection &Выбор Шрифта &Header/Footer &Верхний/Нижний Колонтитул Print Pre&view... Предварительный Про&смотр Печати... &Print... &Печать... &OK &OK &Cancel &Отмена Error: Page size or margins are invalid Ошибка: Размер или поля страницы неверны TreeLine PDF Printer PDF Принтер TreeLine What to print Что печатать &Entire tree &Все Дерево Selected &branches Выбранные &ветви Selected &nodes Выбранные &узлы Included Nodes Включенные Узлы &Include root node &Включить корневой узел Onl&y open node children То&лько открытые дочерние узлы Select &Printer Выберите &Принтер Features Свойства &Draw lines to children &Отображать пути к дочерним узлам &Keep first child with parent По&казывать первый дочерний узел с родителем Indent Отступ Indent Offse&t (line height units) О&тступить при Печати (на количество строк) Letter (8.5 x 11 in.) Letter (8.5 × 11 Inch) Legal (8.5 x 14 in.) Legal (8.5 × 14 Inch) Tabloid (11 x 17 in.) Tabloid (11 × 17 Inch) A3 (279 x 420 mm) A3 (279 × 420 мм) A4 (210 x 297 mm) A4 (210 × 297 мм) A5 (148 x 210 mm) A5 (148 × 210 мм) Custom Size Заданный Размер Inches (in) Дюймы (in.) Millimeters (mm) Миллиметры (мм) Centimeters (cm) Сантиметры (см) &Units &Единицы Измерения Paper &Size &Размер Бумаги &Width: &Ширина: Height: Высота: Orientation Ориентация Portra&it &Книжная Lan&dscape &Альбомная Margins Поля &Left: С&лева: &Top: &Сверху: &Right: С&права: &Bottom: &Снизу: He&ader: &Верхний Колонтитул: Foot&er: Нижний &Колонтитул: Columns Столбцы &Number of columns &Число столбцов Space between colu&mns Расстояние между с&толбцами Default Font Шрифт по Умолчанию &Use TreeLine output view font &Использовать шрифт формы вывода TreeLine Select Font Выберите Шрифт &Font &Шрифт Font st&yle &Начертание Шрифта Si&ze Р&азмер Sample Пример AaBbCcDdEeFfGg...TtUuVvWvXxYyZz АаБбВвГгДдЕеЖж...ЦцШшЩщЬьЭэЮюЯя Header &Right Верхний С&права Header C&enter Верхний по &Центру &Header Left Верхний С&лева Footer &Left Нижний &Слева Footer Righ&t Нижний С&права Footer Ce&nter Нижний по &Центру Fiel&ds По&ля Field For&mat &Поле Формата Header and Footer Верхний и Нижний Колонтитулы Field Format for "{0}" Формат поля для "{0}" Output &Format &Формат Вывода Format &Help &Справка по Форматированию Extra Text Дополнительный текст &Prefix &Приставка &Suffix &Окончание Indent Offse&t (line height units) treenode New Новый fieldformat Text Текст OneLineText Однострочный Текст SpacedText Текст с Междустрочными Интервалами HtmlText Текст с разметкой HTML Math Математическое Поле Numbering Нумерация Number Число Date Дата Time Время DateTime Дата и Время Boolean Логический Тип Combination Комбинация AutoChoice АвтоВыбор Choice Выбор ExternalLink Внешняя Гиперссылка InternalLink Внутренняя Гиперссылка AutoCombination АвтоКомбинация Picture Изображение RegularExpression Регулярное Выражение Now Сегодня и Сейчас Optional Digit # Необязательная Цифра # Required Digit 0 Обязательная Цифра 0 Digit or Space (external) <space> Цифра или Пробел (внешний) <space> Decimal Point . Десятичная Точка . Decimal Comma , Десятичная Запятая , Comma Separator \, Разделитель Запятая \, Dot Separator \. Разделитель в виде Точки \. Space Separator (internal) <space> Пробельный Разделитель (внутренний) <space> Optional Sign - Необязательный Знак - Required Sign + Необходимый Знак + Exponent (capital) E Основание степени (большое) E Exponent (small) e Основание степени (малое) e Number 1 Номер 1 Capital Letter A Заглавная Буква A Small Letter a Строчная буква a Capital Roman Numeral I Заглавная Римская Цифра I Small Roman Numeral i Строчная Римская Цифра i Level Separator / Разделитель Уровней / Section Separator . Разделитель Разделов . "/" Character // "/" Символ // "." Character .. "." Символ .. Outline Example I../A../1../a)/i) Образец Макета I../A../1../a)/i) Section Example 1.1.1.1 Образец Раздела 1.1.1.1 Day (1 or 2 digits) %-d День (1 или 2 цифры) %-d Day (2 digits) %d День (2 цифры) %d Weekday Abbreviation %a Сокращенное Название Дня Недели %a Weekday Name %A День Недели %A Month (1 or 2 digits) %-m Месяц (1 или 2 цифры) %-m Month (2 digits) %m Месяц (2 цифры) %m Month Abbreviation %b Сокращенное Название Месяца %b Month Name %B Название Месяца %B Year (2 digits) %y Год (2 цифры) %y Year (4 digits) %Y Год (4 цифры) %Y Week Number (0 to 53) %-U Номер Недели (от 0 до 53) %-U Day of year (1 to 366) %-j День Года (от 1 до 366) %-j Hour (0-23, 1 or 2 digits) %-H Час (0-23, 1 или 2 цифры) %H Hour (00-23, 2 digits) %H Час (00-23, 2 цифры) %H Hour (1-12, 1 or 2 digits) %-I Час (1-12, 1 или 2 цифры) %-I Hour (01-12, 2 digits) %I Час (01-12, 2 цифры) %I Minute (1 or 2 digits) %-M Минута (1 или 2 цифры) %-M Minute (2 digits) %M Минута (2 цифры) %M Second (1 or 2 digits) %-S Секунда (1 или 2 цифры) %-S Second (2 digits) %S Секундa (2 цифры) %S Microseconds (6 digits) %f Микросекунда (6 цифр) %f AM/PM %p AM/PM Separator / Разделитель / Example 1/2/3/4 Образец 1/2/3/4 yes/no да/нет true/false истина/ложь T/F И/Л Y/N Д/Н Any Character . Любой Символ . End of Text $ Конец Строки $ 0 Or More Repetitions * 0 Или Более Повторов * 1 Or More Repetitions + 1 Или Более Повторов + 0 Or 1 Repetitions ? 0 Или 1 Повтор ? Set of Numbers [0-9] Набор Цифр [0-9] Lower Case Letters [a-z] Буквы в Нижнем Регистре [а-я] Upper Case Letters [A-Z] Буквы в Верхнем Регистре [А-Я] Not a Number [^0-9] Не Цифра [^0-9] Or | ИЛИ | Escape a Special Character \ Экранирование Специального Символа \ DescendantCount Подсчет Потомков spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? Невозможно найти ни aspell.exe, ни ispell.exe или hunspell.exe Выбрать месторасположение? Spell Check Error Ошибка Проверки Правописания Locate aspell.exe, ipsell.exe or hunspell.exe Укажите месторасположение aspell.exe, ispell.exe или hunspell.exe Program (*.exe) Программа (*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed Ошибка Проверки Правописания TreeLine Удостоверьтесь, что aspell, ispell или hunspell установлен Finished checking the branch Continue from the top? Проверка правописания в ветви окончена Продолжить сверху? TreeLine Spell Check Проверка Правописания TreeLine Finished spell checking Проверка правописания окончена Spell Check Проверка Правописания Not in Dictionary Нет в Словаре Word: Слово: Context: Контекст: Suggestions Предложения Ignor&e &Игнорировать &Ignore All Игнорировать &Все &Add &Добавить Add &Lowercase Добавить в &Нижнем регистре &Replace &Заменить Re&place All Заменить &Все &Cancel &Отмена treelocalcontrol Warning - file corruption! Skipped bad child references in the following nodes: Внимание — файл поврежден! Пропущены неверные ссылки на дочерние узлы в следующих узлах: Save changes to {}? Сохранить изменения в {0}? Save changes? Сохранить изменения? Error - could not delete backup file {} Ошибка — невозможно удалить резервную копию файла {0} &Save &Сохранить Save File Сохранить Файл Save the current file Сохранить текущий файл Save &As... Сохранить &Как... Save the file with a new name Сохранить файл под новым именем &Export... &Экспортировать... Export the file in various other formats Экспортировать файл в ряд других форматов Prop&erties... &Свойства... Set file parameters like compression and encryption Назначить такие параметры, как компрессия и шифрование P&rint Setup... Настройка &Печати... Set margins, page size and other printing options Настроить поля, размер страницы и установить другие настройки печати Print Pre&view... Предварительный Про&смотр Печати... Show a preview of printing results Показать предварительный просмотр результатов печати &Print... &Печать... Print tree output based on current options Распечатать вид дерева на выходе в соответствии с текущими настройками Print &to PDF... Печать в &PDF... Export to PDF with current printing options Экспорт в PDF с текущими настройками печати &Undo &Отмена Undo the previous action Отменить предыдущее действие &Redo &Повтор Redo the previous undo Повторить предшествующую отмену Cu&t Вы&резать Cut the branch or text to the clipboard Вырезать ветвь или текст и поместить в буфер обмена &Copy &Копировать Copy the branch or text to the clipboard Копировать ветвь или текст в буфер обмена &Paste &Вставить Paste nodes or text from the clipboard Вставить узлы или текст из буфера обмена Pa&ste Plain Text &Вставить Простой Текст Paste non-formatted text from the clipboard Вставить неформатированный текст из буфера обмена Paste C&hild Вставить &Дочерний Узел Paste a child node from the clipboard Вставить дочерний узел из буфера обмена Paste Sibling &Before Вставить Сестринский Узел &Перед Paste a sibling before selection Вставить сестринский узел перед выбранным Paste Sibling &After Вставить Сестринский Узел &После Paste a sibling after selection Вставить сестринский узел после выбранного Paste Cl&oned Child Вставить К&лонированный Дочерний Узел Paste a child clone from the clipboard Вставить клон дочернего узла из буфера обмена Paste Clo&ned Sibling Before Вставить К&лонированный Сестринский Узел Перед Paste a sibling clone before selection Вставить клон сестринского узла перед выбранным Paste Clone&d Sibling After Вставить К&лонированный Сестринский Узел После Paste a sibling clone after selection Вставить клон сестринского узла после выбранного &Rename &Переименовать Rename the current tree entry title Переименовать заголовок текущего элемента дерева Add &Child Добавить &Дочерний Узел Add new child to selected parent Добавить новый дочерний узел к выбранному родителю Insert Sibling &Before Создать Сестринский Узел П&еред Insert new sibling before selection Создать новый сестринский узел перед выбранным Insert Sibling &After Создать Сестринский Узел &После Insert new sibling after selection Создать новый сестринский узел после выбранного &Delete Node &Удалить Узел Delete the selected nodes Удалить выбранные узлы &Indent Node &Вдвинуть Узел Indent the selected nodes Вдвинуть выбранные узлы &Unindent Node В&ыдвинуть Узел Unindent the selected nodes Выдвинуть выбранные узлы &Move Up &Переместить Вверх Move the selected nodes up Переместить выбранные узлы вверх M&ove Down Пе&реместить Вниз Move the selected nodes down Переместить выбранные узлы вниз Move &First Переместить в &Начало [внутри родителя] Move the selected nodes to be the first children Переместить выбранные узлы на место первых дочерних Move &Last Переместить в &Конец [внутри родителя] Move the selected nodes to be the last children Переместить выбранные узлы на место последних дочерних &Set Node Type &Назначить Тип Узла Set the node type for selected nodes Назначить тип узла для выбранных узлов Set Node Type Назначить Тип Узла Copy Types from &File... Копировать Типы из &Файла... Copy the configuration from another TreeLine file Скопировать конфигурацию из другого файла Treeline &Regenerate References &Обновить Ссылки Force update of all conditional types & math fields Принудительное обновление всех условных типов & полей математических полей Clone All &Matched Nodes Клонировать Все &Подошедшие Узлы Convert all matching nodes into clones Конвертировать все подошедшие узлы в клоны &Detach Clones &Отделить Клоны Detach all cloned nodes in current branches Отделить все клонированные узлы в текущих ветвях Flatten &by Category Свести на Один Уровень &по Категории Collapse descendants by merging fields Объединить потомков слиянием полей Add Category &Level... Добавить &Уровень Категории... Insert category nodes above children Создать узлы категорий над дочерними узлами S&wap Category Levels П&оменять Местами Уровни Категории Swap child and grandchild category nodes Поменять узлы дочерней и внучатой категорий &Spell Check... &Проверка Правописания... Spell check the tree's text data Проверить правописание текста в дереве &Bold Font &Жирный Шрифт Set the current or selected font to bold Сделать текущий или выбранный шрифт жирным &Italic Font &Наклонный Шрифт Set the current or selected font to italic Сделать текущий или выбранный шрифт наклонным U&nderline Font Под&черкнутый Шрифт Set the current or selected font to underline Сделать текущий или выбранный текст подчеркнутым St&rikethrough Font &Зачеркнутый Шрифт Set the current or selected font to strikethough Сделать текущий или выбранный текст зачеркнутым &Font Size &Размер Шрифта Set size of the current or selected text Назначить размер текущего или выбранного текста Large Большой Small Маленький Larger Больший Default По Умолчанию Largest Наибольший Set Font Size Установить Размер Шрифта Font C&olor... Ц&вет Шрифта... Set the color of the current or selected text Назначить цвет текущего или выбранного текста &External Link... &Внешняя Гиперссылка... Add or modify an extrnal web link Добавить или изменить внешннюю гиперссылку на web-страницу Internal &Link... &Внутреняя Гиперссылка... Add or modify an internal node link Добавить или изменить внутреннюю гиперссылку на узел Insert &Date Вставить &Дату Insert current date as text Вставить текущую дату как текст Clear For&matting Очистить Фо&рматирование Clear current or selected text formatting Очистить настройки формата текущего или выбранного текста &New Window &Новое Окно Open a new window for the same file Открыть этот же файл в новом окне Error - could not write to {} Ошибка — не могу записать в {} File saved Файл сохранен TreeLine - Save As TreeLine — Сохранить Как Error - could not write to file Ошибка — невозможно записать файл TreeLine - Open Configuration File TreeLine — Открыть Файл Конфигурации Error - could not read file {0} Ошибка — не могу прочитать файл {0} Converted {0} branches into clones Конвертировано {0} ветвей в клоны No identical nodes found Идентичные узлы не найдены Cannot expand without common fields Невозможно расширить без общих полей Category Fields Поля Категории Select fields for new level Выберите поля для нового уровня Warning - file corruption! Skipped bad child references in the following nodes: treeformats DEFAULT ПО УМОЛЧАНИЮ FILE ФАЙЛ TYPE ТИП TitleFormat ФорматЗаголовка OutputFormat ФорматВывода SpaceBetween ПробелМежду FormatHtml ФорматироватьHTML Bullets Маркеры Table Таблица ChildType ДочернийТип Icon Значок GenericType ОбщийТип ConditionalRule УсловноеПравило ListSeparator РазделительЭлементовСписка ChildTypeLimit ОграничениеДочернегоТипа FIELD ПОЛЕ FieldType Тип Поля Format Формат Prefix Приставка Suffix Окончание InitialValue НачальноеЗначение NumLines НумСтроки SortKeyNum НомСортКл SortForward СортВперед EvalHtml ОпредHTML imports &Tab indented text, one node per line Текст с &Tab-отступами, один узел на строку Co&mma delimited (CSV) text table with level column && header row Текстовая таблица, размеченная за&пятыми (CSV), со столбцом уровней && строкой заголовка Comma delimited (CSV) text table &with header row Текстовая таблица, размеченная за&пятыми (CSV) со строкой заголовка Tab delimited text table with header &row Текстовая таблица, размеченная Tab, со ст&рокой заголовка Plain text, one &node per line (CR delimited) Простой текст, один &узел на строку (ограниченный переносом строки) Plain text &paragraphs (blank line delimited) &Простой текст с абзацами (разграничены пустыми строками) &HTML bookmarks (Mozilla Format) Закладки &HTML (в формате Mozilla) &XML bookmarks (XBEL format) Закладки &XML (в формате XBEL) Other Другие Old Tree&Line File (1.x or 2.x) Файл Tree&Line Старой Версии (1.x или 2.x) Treepad &file (text nodes only) &Файл Treepad (только текстовые узлы) &Generic XML (non-TreeLine file) XML &Общего Вида (не файл Treeline) Open &Document (ODF) outline Открыть Структуру &Документа (ODF) FOLDER ПАПКА BOOKMARK ЗАКЛАДКА SEPARATOR РАЗДЕЛИТЕЛЬ Link Гиперссылка Text Текст Import File Импортировать Файл Choose Import Method Выберите Способ Импортирования Invalid File Неверный Файл "{0}" is not a valid TreeLine file. Use an import filter? "{0}" не являвляется файлом, подходящим для Treeline. Применить фильтр для импорта? TreeLine - Import File TreeLine — Импортировать Файл Error - could not read file {0} Ошибка — невозможно прочитать файл {0} Error - improper format in {0} Ошибка — неверный формат в {0} TABLE ТАБЛИЦА Invalid level number on line {0} Неверный номер уровня в строке {0} Bad CSV format on Line {0} Неверный формат CSV в строке {0} Invalid level structure Неверная структура уровня Too many entries on Line {0} Слишком много элементов в Строке {0} Bookmarks Закладки No headings found treestructure Main Главный nodeformat Name Имя treemaincontrol Warning: Could not create local socket Внимание: Невозможно создать локальный сокет missing directory отсутствующая директория Error - could not write config file to {} Ошибка — не могу записать файл конфигурации в {} Error - could not read file {0} Ошибка — невозможно прочитать файл {0} Error - invalid TreeLine file {0} Ошибка — неверный файл файл Treeline {0} Backup file "{}" exists. A previous session may have crashed Имеется резервная копия файла {}. Возможно предыдущая сессия была аварийно завершена &Restore Backup &Восстановить из резервной копии файла &Delete Backup Удалить файл &Резервной Копии &Cancel File Open &Отмена Открытия Файла Error - could not rename "{0}" to "{1}" Ошибка — невозможно переименовать {0} в {1} Error - could not remove backup file {} Ошибка — невозможно удалить резервную копию файла &New... &Новый... New File Новый Файл Start a new file Создать новый файл &Open... &Открыть... Open File Открыть Файл Open a file from disk Открыть файл с диска Open Sa&mple... Открыть П&ример... Open Sample Открыть Пример Open a sample file Открыть файл примера &Import... &Импортировать... Open a non-TreeLine file Открыть не-Treeline файл &Quit &Выход Exit the application Выйти из приложения &Configure Data Types... &Настроить Типы Данных... Modify data types, fields & output lines Изменить типы данных, поля & строки вывода Show C&onfiguration Structure... Показать С&конфигурированную Структуру... Show read-only visualization of type structure Показать доступное только для чтения представление структуры типов Sor&t Nodes... &Сортировать Узлы... Define node sort operations Задать параметры сортировки узлов Update &Numbering... Обновить &Нумерацию... Update node numbering fields Обновить поля нумерации &Find Text... &Поиск Текста... Find text in node titles & data Найти текст в заголовках узлов & данных &Conditional Find... &Условный Поиск... Use field conditions to find nodes Использовать условия выбора полей для фильтрации узлов Find and &Replace... Поиск и &Замена... Replace text strings in node data Заменить текстовые строки в узлах &Text Filter... &Текстовый Фильтр... Filter nodes to only show text matches Фильтровать узлы, показав только совпадения текста C&onditional Filter... &Условный Фильтр... Use field conditions to filter nodes Использовать условия выбора полей для фильтрации узлов &General Options... &Общие Параметры... Set user preferences for all files Назначить установки пользователя для всех файлов Set &Keyboard Shortcuts... &Назначить Горячие Клавиши... Customize keyboard commands Настроить команды клавиатуры C&ustomize Toolbars... &Настроить Панели инструментов... Customize toolbar buttons Настроить кнопки на панели инструментов Customize Fo&nts... Настроить Ш&рифты... Customize fonts in various views Настроить шрифты для разных форм просмотра Custo&mize Colors... Настроить &Цвета... Customize GUI colors and themes Настроить цвета и темы GUI &Select All &Выбрать все Select all text in an editor Выбрать весь текст в редакторе &Basic Usage... &Основы... Display basic usage instructions Показать основные используемые инструкции &Full Documentation... &Полная Документация... Open a TreeLine file with full documentation Открыть файл Treeline, содержащий полную документацию &About TreeLine... &О TreeLine... Display version info about this program Показать сведения о версии программы &Select Template &Выбрать Шаблон TreeLine - Open File TreeLine — Открыть Файл Open Sample File Открыть Файл Примера &Select Sample &Выбрать Пример Conditional Find Условный Поиск Conditional Filter Условный Фильтр General Options Общие Параметры Error - basic help file not found Ошибка — файл справки по основам использования не найден TreeLine Basic Usage Основы использования TreeLine Error - documentation file not found Ошибка — файл документации не найден TreeLine version {0} Версия TreeLine {0} written by {0} автор {0} Library versions: Версии библиотек: helpview Tools Инструменты &Back &Назад &Forward &Вперед &Home &К Началу Find: Найти: Find &Previous Найти &Предыдущий Find &Next &Найти Следующий Text string not found Текстовая строка не найдена treewindow Data Output Вывод Данных Data Edit Редактор Данных Title List Список Заголовков &Expand Full Branch &Развернуть Всю Ветвь Expand all children of the selected nodes Раскрыть все дочерние узлы выбранных узлов &Collapse Full Branch &Свернуть Всю Ветвь Collapse all children of the selected nodes Свернуть все дочерние узлы выбранных узлов &Previous Selection &Предыдущий Выбор Return to the previous tree selection Вернуться к предыдущему выбору в дереве &Next Selection &Следующий Выбор Go to the next tree selection in history Перейти к следующему выбору в истории Show Data &Output Показать &Вывод Данных Show data output in right view Показать вывод данных в форме справа Show Data &Editor Показать &Редактор Данных Show data editor in right view Показать редактор данных в форме справа Show &Title List Показать Список &Заголовков Show title list in right view Показать список заголовков в форме справа Show &Breadcrumb View Показать &Навигационную цепочку Toggle showing breadcrumb ancestor view Переключить на показ навигационной цепочки к предку &Show Child Pane &Показать Панель Дочернего Узла Toggle showing right-hand child views Переключить на показ дочерних узлов в форме справа Show Output &Descendants Показать Вывод &Потомков Toggle showing output view indented descendants Переключить показ потомков с отступами &Close Window &Закрыть Окно Close this window Закрыть это окно Start Incremental Search Начать Пошаговый Поиск Next Incremental Search Пошагово Искать Следующий Previous Incremental Search Пошагово Искать Предыдущий &File &Файл &Edit &Правка &Node &Узел &Data &Данные &Tools &Инструменты Fo&rmat &Формат &View &Вид &Window &Окно &Help &Справка exports Bookmarks Закладки TreeLine - Export HTML TreeLine — Экспорт в HTML Error - export template files not found. Check your TreeLine installation. Ошибка — файлы шаблона для экспорта не найдены. Проверьте вашу установку Treeline. Error - cannot link to unsaved TreeLine file. Save the file and retry. Ошибка — невозможно установить ссылку на несохраненный файл Treeline. Сохраните файл и попробуйте снова. Warning - no relative path from "{0}" to "{1}". Continue with absolute path? Внимание — отсутствует относительный путь от{0} к {1}. Продолжить, используя абсолютный путь? TreeLine - Export Text Titles TreeLine — Экспорт Заголовков Текста TreeLine - Export Plain Text TreeLine — Экспорт в Простой Текст TreeLine - Export Text Tables TreeLine — Экспорт в Текстовые Таблицы TreeLine - Export TreeLine Subtree TreeLine — Экспорт в Поддерево Treeline TreeLine - Export Generic XML TreeLine — Экспорт в XML Общего Вида TreeLine - Export ODF Text TreeLine — Экспорт в ODF Текст TreeLine - Export HTML Bookmarks TreeLine — Экспорт в Закладки HTML TreeLine - Export XBEL Bookmarks TreeLine — Экспорт в Закладки XBEL Parent Родитель &HTML &HTML &Text &Текст Tree&Line Tree&Line &ODF Outline Структура &ODF &XML (generic) &XML (общего вида) Book&marks За&кладки &Single HTML page Одиночная страница &HTML Single &HTML page with navigation pane Одиночная страница &HTML с панелью навигации Multiple HTML &pages with navigation pane Многостраничный &HTML с панелью навигации Multiple HTML &data tables Многостраничный HTML с таблицами &данных Live tree view, linked to TreeLine file (for web server) Интерактивный просмотр дерева, привязанного к файлу Treeline (для веб-сервера) Live tree view, single file (embedded data) Интерактивный просмотр дерева, одиночный файл (встроенные данные) &Tabbed title text &Табулированный текст заголовков &Unformatted output of all text &Неформатированный вывод всего текста &Comma delimited (CSV) table of descendants (level numbers) Таблица потомков (номера уровней), размеченная &запятыми (CSV) Comma &delimited (CSV) table of children (single level) Таблица дочерних узлов, размеченная &запятыми (CSV) (единственный уровень) Tab &delimited table of children (&single level) Таблица дочерних узлов, размеченная Tab (&единственный уровень) &Old TreeLine (2.0.x) &Старая версия Treeline (2.0.x) &TreeLine Subtree Поддерево &TreeLine &HTML format bookmarks Закладки в формате &HTML &XBEL format bookmarks Закладки в формате &XBEL File Export Экспорт Файла Choose export format type Выберите тип формата для экспорта Choose export format subtype Выберите подтип формата для экспорта Choose export options Выберите настройки экспорта What to Export Что Экспортировать &Entire tree &Все Дерево Selected &branches Выбранные &ветви Selected &nodes Выбранные &узлы Other Options Другие Настройки &Include root nodes &Включить корневые узлы &Only open node children &Только открытые дочерние узлы Include &print header && footer &Включить верхний && нижний колонтитулы &Columns &Столбцы Navigation pane &levels &Уровни навигационной панели Must select nodes prior to export Перед экспортом должны быть выбраны узлы Error - export template files not found. Check your TreeLine installation. optiondefaults Monday Понедельник Wednesday Среда Tuesday Вторник Thursday Четверг Friday Пятница Sunday Воскресенье Saturday Суббота Startup Condition Условия Запуска Программы Automatically open last file used Автоматически открывать последний файл Show breadcrumb ancestor view Включить просмотр навигационной цепочки к предку Show child pane in right hand views Показывать панель дочернего узла в форме справа Show descendants in output view Показывать потомков в окне вывода Restore tree view states of recent files Восстанавливать состояние последнего файла Remove inaccessible recent file entries Удалять недоступные данные, вошедшие в последний файл Restore previous window geometry Восстанавливать установки окна при запуске Features Available Доступные Функции Open files in new windows Открывать файлы в новых окнах Minimize application to system tray Сворачивать приложение в системный лоток Activate data editors on mouse hover Активировать поля редактора данных при наведении мышью Limit data editor height to window size Ограничить высоту редактора данных размером окна Click node to rename Переименовывать узлы по щелчку мыши Rename new nodes when created Редактировать имена новых узлов при создании Tree drag && drop available Разрешить перетаскивание элементов дерева мышью Indent (pretty print) TreeLine JSON files Смещать вправо (для красивой печати) JSON файлы Treeline Show icons in the tree view Показывать значки в дереве Show math fields in the Data Edit view Показывать математические поля в Редакторе Данных Show numbering fields in the Data Edit view Показывать поля нумерации в Редакторе Данных Undo Memory Сохранять для Восстановления Number of undo levels Число возможных отмен действий Auto Save АвтоСохранение Minutes between saves (set to 0 to disable) Количество минут между сохранениями (установите 0 для отключения) Recent Files Последние Файлы Number of recent files in the file menu Число последних файлов в файловом меню Times Время Data Editor Formats Форматы Редактора Данных Dates Дата First day of week Первый день недели Appearance Вид Child indent offset (in font height units) Величина сдвига дочерних узлов (в единицах размера шрифта) First day of week Child indent offset (in font height units) globalref All TreeLine Files Все Файлы Treeline TreeLine Files Файлы TreeLine TreeLine Files - Compressed Файлы TreeLine — Сжаты TreeLine Files - Encrypted Файлы TreeLine — Зашифрованы Old TreeLine Files Файлы Старой Версии TreeLine All Files Все Файлы HTML Files Файлы HTML Text Files Текстовые Файлы XML Files Файлы XML CSV (Comma Delimited) Files Файлы CSV (Размечены Запятыми) ODF Text Files Файлы ODF Treepad Files Файлы Treepad PDF Files Файлы PDF treeview Search for: Найти: Search for: {0} Найти: {0} Search for: {0} (not found) Найти: {0} (не найдено) Next: {0} Следующий: {0} Next: {0} (not found) Следующий: {0} (не найдено) Filtering by "{0}", found {1} nodes Отфильтровано по "{0}", узлов найдено {0} Conditional filtering, found {0} nodes Условная фильтрация, узлов найдено {0} titlelistview Select in Tree Выбрать в Дереве matheval Illegal "{}" characters Недопустимые "{}" символы Invalid field modifiers Неверные модификаторы поля Child references must be combined in a function Ссылки на дочерние узлы должны быть включены в функцию Illegal syntax in equation Недопустимый синтаксис в выражении Illegal function present: {0} Недопустимая функция: {0} Illegal object type or operator: {0} Недопустимый тип объекта или оператор: {0} printdata Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Внимание: Выбранный размер и поля страницы не поддерживается данным принтером. Сохранить настройки страницы? Warning: Page size setting unsupported on current printer. Save adjustment? Внимание: Выбранный размер страницы не поддерживается данным принтером. Сохранить настройки? Warning: Margin settings unsupported on current printer. Save adjustments? Внимание: Настройки полей не поддерживаются данным принтером. Сохранить настройки? Error initializing printer Ошибка инициализации принтера TreeLine - Export PDF TreeLine — Экспорт в PDF Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Warning: Page size setting unsupported on current printer. Save adjustment? Warning: Margin settings unsupported on current printer. Save adjustments? TreeLine-3.2.1/working/translations/treeline_xx.ts000066400000000000000000005544431506556630100223510ustar00rootroot00000000000000 conditional starts with ends with contains True False and or [All Types] Node Type &Add New Rule &Remove Rule &OK &Cancel Find &Previous Find &Next &Filter &End Filter &Close No conditional matches were found Rule {0} Saved Rules Name: &Load &Save &Delete configdialog Configure Data Types T&ype List Typ&e Config Field &List &Field Config O&utput &Show Advanced &OK &Apply &Reset &Cancel &Hide Advanced Error - circular reference in math field equations Add or Remove Data Types &New Type... Co&py Type... Rena&me Type... &Delete Type Add Type Enter new type name: Copy Type &Derive from original Rename Type Rename from {} to: Cannot delete data type being used by nodes [None] no type set &Data Type Default Child &Type Icon Change &Icon Output Options Add &blank lines between nodes Allow &HTML rich text in format Add text bullet&s Use a table for field &data Combination && Child List Output &Separator Derived from &Generic Type Automatic Types None Modify Co&nditional Types Create Co&nditional Types Set Types Conditionally Modify &Field List Name Type Sort Key Move U&p Move Do&wn &New Field... Rena&me Field... Dele&te Field Sort &Keys... fwd rev Add Field Enter new field name: Rename Field File Info Reference F&ield &Field Type Outpu&t Format Format &Help Extra Text &Prefix Suffi&x Default &Value for New Nodes Editor Height Num&ber of text lines Math Equation Define Equation F&ield List &Title Format Out&put Format Other Field References Reference Le&vel Refere&nce Type The name cannot be empty The name must start with a letter The name cannot start with "xml" The name cannot contain spaces The following characters are not allowed: {} The name was already used Set Data Type Icon Clear &Select forward reverse Sort Key Fields Available &Fields &Sort Criteria Field Direction Move &Up &Move Down Flip &Direction Self Reference Parent Reference Root Reference Child Reference Child Count Date Result Time Result add subtract multiply divide floor divide modulus power sum of items maximum minimum average absolute value square root natural logarithm base-10 logarithm factorial round to num digits lower integer higher integer truncated integer floating point sine of radians cosine of radians tangent of radians arc sine arc cosine arc tangent radians to degrees degrees to radians pi constant natural log constant Define Math Field Equation Field References Reference &Level Reference &Type Available &Field List &Result Type Description &Equation Equation error: {} Boolean Result Text Result Arithmetic Operators Comparison Operators Text Operators equal to less than greater than less than or equal to greater than or equal to not equal to true value, condition, false value true if 1st text arg starts with 2nd arg true if 1st text arg ends with 2nd arg true if 1st text arg contains 2nd arg concatenate text join text using 1st arg as separator convert text to upper case convert text to lower case in 1st arg, replace 2nd arg with 3rd arg Operations O&perator Type Oper&ator List logical and logical or Output HTML Evaluate &HTML tags Child Type Limits [All Types Available] &Select All Select &None Number Result Count Number of Children dataeditors Today's &Date &Open Link Open &Folder External Link Scheme &Browse for File File Path Type Absolute Relative Address Display Name &OK &Cancel TreeLine - External Link File &Go to Target Internal Link &Open Picture Picture Link TreeLine - Picture File Set to &Now Clear &Link (Click link target in tree) link exports Bookmarks TreeLine - Export HTML TreeLine - Export Text Titles TreeLine - Export Plain Text TreeLine - Export Text Tables TreeLine - Export Generic XML TreeLine - Export TreeLine Subtree TreeLine - Export ODF Text TreeLine - Export HTML Bookmarks TreeLine - Export XBEL Bookmarks &HTML &Text &ODF Outline Book&marks &Single HTML page Single &HTML page with navigation pane Multiple HTML &pages with navigation pane Multiple HTML &data tables &Tabbed title text &Unformatted output of all text &HTML format bookmarks &XBEL format bookmarks File Export Choose export format type Choose export format subtype Choose export options What to Export &Entire tree Selected &branches Selected &nodes Other Options &Only open node children Include &print header && footer &Columns Navigation pane &levels Error - export template files not found. Check your TreeLine installation. Error - cannot link to unsaved TreeLine file. Save the file and retry. Warning - no relative path from "{0}" to "{1}". Continue with absolute path? Parent Tree&Line &XML (generic) Live tree view, linked to TreeLine file (for web server) Live tree view, single file (embedded data) &Comma delimited (CSV) table of descendants (level numbers) Comma &delimited (CSV) table of children (single level) Tab &delimited table of children (&single level) &Old TreeLine (2.0.x) &TreeLine Subtree &Include root nodes Must select nodes prior to export fieldformat Text HtmlText OneLineText SpacedText Number Math Numbering Boolean Date Time Choice AutoChoice Combination AutoCombination ExternalLink InternalLink Picture RegularExpression Now Optional Digit # Required Digit 0 Digit or Space (external) <space> Decimal Point . Decimal Comma , Space Separator (internal) <space> Optional Sign - Required Sign + Exponent (capital) E Exponent (small) e Number 1 Capital Letter A Small Letter a Capital Roman Numeral I Small Roman Numeral i Level Separator / Section Separator . "/" Character // "." Character .. Outline Example I../A../1../a)/i) Section Example 1.1.1.1 Separator / Example 1/2/3/4 yes/no true/false T/F Y/N Any Character . End of Text $ 0 Or More Repetitions * 1 Or More Repetitions + 0 Or 1 Repetitions ? Set of Numbers [0-9] Lower Case Letters [a-z] Upper Case Letters [A-Z] Not a Number [^0-9] Or | Escape a Special Character \ DateTime Day (1 or 2 digits) %-d Day (2 digits) %d Weekday Abbreviation %a Weekday Name %A Month (1 or 2 digits) %-m Month (2 digits) %m Month Abbreviation %b Month Name %B Year (2 digits) %y Year (4 digits) %Y Week Number (0 to 53) %-U Day of year (1 to 366) %-j Hour (0-23, 1 or 2 digits) %-H Hour (00-23, 2 digits) %H Hour (1-12, 1 or 2 digits) %-I Hour (01-12, 2 digits) %I Minute (1 or 2 digits) %-M Minute (2 digits) %M Second (1 or 2 digits) %-S Second (2 digits) %S Microseconds (6 digits) %f AM/PM %p Comma Separator \, Dot Separator \. DescendantCount genboolean true false yes no globalref TreeLine Files TreeLine Files - Compressed TreeLine Files - Encrypted All Files HTML Files Text Files XML Files ODF Text Files Treepad Files PDF Files CSV (Comma Delimited) Files All TreeLine Files Old TreeLine Files helpview Tools &Back &Forward &Home Find: Find &Previous Find &Next Text string not found imports &Tab indented text, one node per line Tab delimited text table with header &row Plain text &paragraphs (blank line delimited) Treepad &file (text nodes only) &Generic XML (non-TreeLine file) Open &Document (ODF) outline &HTML bookmarks (Mozilla Format) &XML bookmarks (XBEL format) FOLDER BOOKMARK SEPARATOR Link Text Import File Choose Import Method Invalid File "{0}" is not a valid TreeLine file. Use an import filter? TreeLine - Import File Error - could not read file {0} Error - improper format in {0} TABLE Bookmarks Too many entries on Line {0} Plain text, one &node per line (CR delimited) Bad CSV format on Line {0} Co&mma delimited (CSV) text table with level column && header row Comma delimited (CSV) text table &with header row Other Old Tree&Line File (1.x or 2.x) Invalid level number on line {0} Invalid level structure No headings found matheval Illegal "{}" characters Child references must be combined in a function Illegal syntax in equation Illegal function present: {0} Illegal object type or operator: {0} Invalid field modifiers miscdialogs &OK &Cancel Fields File Properties File Storage &Use file compression Use file &encryption Spell Check Language code or dictionary (optional) Math Fields &Treat blank fields as zeros Encrypted File Password Type Password for "{0}": Type Password: Re-Type Password: Remember password during this session Zero-length passwords are not permitted Re-typed password did not match Default - Single Line Text &Search Text What to Search Full &data &Titles only How to Search &Key words Key full &words F&ull phrase &Regular expression Find Find &Previous Find &Next Filter &Filter &End Filter &Close Error - invalid regular expression Search string "{0}" not found Find and Replace Replacement &Text Any &match Full &words Re&gular expression &Node Type N&ode Fields &Find Next &Replace Replace &All [All Types] [All Fields] Search text "{0}" not found Error - replacement failed Replaced {0} matches Sort Nodes What to Sort &Entire tree Selected &branches Selection's childre&n Selection's &siblings Sort Method &Predefined Key Fields Node &Titles Sort Direction &Forward &Reverse &Apply Update Node Numbering What to Update &Selection's children Root Node Include top-level nodes Handling Nodes without Numbering Fields &Ignore and skip &Restart numbers for next siblings Reserve &numbers TreeLine Numbering No numbering fields were found in data types File Menu File Edit Menu Edit Node Menu Node Data Menu Data Tools Menu Tools View Menu View Window Menu Window Help Menu Help Keyboard Shortcuts &Restore Defaults Key {0} is already used Clear &Key --Separator-- Customize Toolbars Toolbar &Size Small Icons Large Icons Toolbar Quantity &Toolbars A&vailable Commands Tool&bar Commands Move &Up Move &Down Tree View Font Output View Font Editor View Font No menu TreeLine - Serious Error A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. Format Menu Format Customize Fonts &Use system default font App Default Font &Use app default font Externally Modified File &Overwrite File &Cancel Save File was externally modified at {} nodeformat Name optiondefaults Monday Tuesday Wednesday Thursday Friday Saturday Sunday Startup Condition Automatically open last file used Show descendants in output view Restore tree view states of recent files Restore previous window geometry Features Available Open files in new windows Click node to rename Rename new nodes when created Tree drag && drop available Show icons in the tree view Show math fields in the Data Edit view Show numbering fields in the Data Edit view Undo Memory Number of undo levels Auto Save Minutes between saves (set to 0 to disable) Recent Files Number of recent files in the file menu Data Editor Formats Times Dates First day of week Appearance Child indent offset (in font height units) Show breadcrumb ancestor view Show child pane in right hand views Remove inaccessible recent file entries Activate data editors on mouse hover Minimize application to system tray Indent (pretty print) TreeLine JSON files Limit data editor height to window size options Choose configuration file location User's home directory (recommended) Program directory (for portable use) &OK &Cancel printdata Error initializing printer TreeLine - Export PDF Warning: Page size and margin settings unsupported on current printer. Save page adjustments? Warning: Page size setting unsupported on current printer. Save adjustment? Warning: Margin settings unsupported on current printer. Save adjustments? printdialogs Print Preview Fit Width Fit Page Zoom In Zoom Out Previous Page Next Page Single Page Facing Pages Print Setup Print Printing Setup &General Options Page &Setup &Font Selection &Header/Footer Print Pre&view... &Print... &OK &Cancel What to print &Entire tree Selected &branches Selected &nodes Included Nodes &Include root node Onl&y open node children Features &Draw lines to children &Keep first child with parent Indent Indent Offse&t (line height units) Letter (8.5 x 11 in.) Legal (8.5 x 14 in.) Tabloid (11 x 17 in.) A3 (279 x 420 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) Custom Size Inches (in) Millimeters (mm) Centimeters (cm) &Units Paper &Size &Width: Height: Orientation Portra&it Lan&dscape Margins &Left: &Top: &Right: &Bottom: He&ader: Foot&er: Columns &Number of columns Space between colu&mns Default Font &Use TreeLine output view font Select Font &Font Font st&yle Si&ze Sample AaBbCcDdEeFfGg...TtUuVvWvXxYyZz &Header Left Header C&enter Header &Right Footer &Left Footer Ce&nter Footer Righ&t Fiel&ds Field For&mat Header and Footer Field Format for "{0}" Output &Format Format &Help Extra Text &Prefix &Suffix Error: Page size or margins are invalid TreeLine PDF Printer Select &Printer spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? Spell Check Error Locate aspell.exe, ipsell.exe or hunspell.exe Program (*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed TreeLine Spell Check Finished spell checking Spell Check Not in Dictionary Word: Context: Suggestions Ignor&e &Ignore All &Add Add &Lowercase &Replace Re&place All &Cancel Finished checking the branch Continue from the top? titlelistview Select in Tree treeformats DEFAULT FILE TYPE FIELD FieldType TitleFormat OutputFormat SpaceBetween FormatHtml Bullets Table ChildType Icon GenericType ConditionalRule ListSeparator ChildTypeLimit Format Prefix Suffix InitialValue NumLines SortKeyNum SortForward EvalHtml treelocalcontrol Error - could not delete backup file {} Save changes to {}? Save changes? &Save Save File Save the current file Save &As... Save the file with a new name &Export... Export the file in various other formats Prop&erties... Set file parameters like compression and encryption P&rint Setup... Set margins, page size and other printing options Print Pre&view... Show a preview of printing results &Print... Print tree output based on current options Print &to PDF... Export to PDF with current printing options &Undo Undo the previous action &Redo Redo the previous undo Cu&t Cut the branch or text to the clipboard &Copy Copy the branch or text to the clipboard &Paste Paste nodes or text from the clipboard Paste non-formatted text from the clipboard &Bold Font Set the current or selected font to bold &Italic Font Set the current or selected font to italic U&nderline Font Set the current or selected font to underline &Font Size Set size of the current or selected text Small Default Large Larger Largest Set Font Size Font C&olor... Set the color of the current or selected text &External Link... Add or modify an extrnal web link Internal &Link... Add or modify an internal node link Clear For&matting Clear current or selected text formatting &Rename Rename the current tree entry title Insert Sibling &Before Insert new sibling before selection Insert Sibling &After Insert new sibling after selection Add &Child Add new child to selected parent &Delete Node Delete the selected nodes &Indent Node Indent the selected nodes &Unindent Node Unindent the selected nodes &Move Up Move the selected nodes up M&ove Down Move the selected nodes down Move &First Move the selected nodes to be the first children Move &Last Move the selected nodes to be the last children &Set Node Type Set the node type for selected nodes Set Node Type Copy Types from &File... Copy the configuration from another TreeLine file Flatten &by Category Collapse descendants by merging fields Add Category &Level... Insert category nodes above children &Spell Check... &New Window Open a new window for the same file Error - could not write to {} TreeLine - Save As Error - could not write to file TreeLine - Open Configuration File Error - could not read file {0} Cannot expand without common fields Category Fields Select fields for new level File saved Pa&ste Plain Text Paste C&hild Paste a child node from the clipboard Paste Sibling &Before Paste a sibling before selection Paste Sibling &After Paste a sibling after selection Paste Cl&oned Child Paste a child clone from the clipboard Paste Clo&ned Sibling Before Paste a sibling clone before selection Paste Clone&d Sibling After Paste a sibling clone after selection Clone All &Matched Nodes Convert all matching nodes into clones &Detach Clones Detach all cloned nodes in current branches S&wap Category Levels Swap child and grandchild category nodes Converted {0} branches into clones No identical nodes found Warning - file corruption! Skipped bad child references in the following nodes: Spell check the tree's text data &Regenerate References Force update of all conditional types & math fields Insert &Date Insert current date as text St&rikethrough Font Set the current or selected font to strikethough treemaincontrol Warning: Could not create local socket Error - could not write config file to {} Error - could not read file {0} Backup file "{}" exists. A previous session may have crashed &Restore Backup &Delete Backup &Cancel File Open Error - could not rename "{0}" to "{1}" Error - could not remove backup file {} &New... New File Start a new file &Open... Open File Open a file from disk Open Sa&mple... Open Sample Open a sample file &Import... Open a non-TreeLine file &Quit Exit the application &Select All Select all text in an editor &Configure Data Types... Modify data types, fields & output lines Sor&t Nodes... Define node sort operations Update &Numbering... Update node numbering fields &Find Text... Find text in node titles & data &Conditional Find... Use field conditions to find nodes Find and &Replace... Replace text strings in node data &Text Filter... Filter nodes to only show text matches C&onditional Filter... Use field conditions to filter nodes &General Options... Set user preferences for all files Set &Keyboard Shortcuts... Customize keyboard commands C&ustomize Toolbars... Customize toolbar buttons Customize Fo&nts... Customize fonts in various views &Basic Usage... Display basic usage instructions &Full Documentation... Open a TreeLine file with full documentation &About TreeLine... Display version info about this program &Select Template TreeLine - Open File Open Sample File &Select Sample Conditional Find Conditional Filter General Options Error - basic help file not found TreeLine Basic Usage Error - documentation file not found Error - invalid TreeLine file {0} TreeLine version {0} written by {0} Library versions: missing directory Show C&onfiguration Structure... Show read-only visualization of type structure Custo&mize Colors... Customize GUI colors and themes treenode New treestructure Main treeview Filtering by "{0}", found {1} nodes Conditional filtering, found {0} nodes Search for: Search for: {0} Search for: {0} (not found) Next: {0} Next: {0} (not found) treewindow Data Output Data Edit Title List &Expand Full Branch Expand all children of the selected nodes &Collapse Full Branch Collapse all children of the selected nodes &Previous Selection Return to the previous tree selection &Next Selection Go to the next tree selection in history Show Data &Output Show data output in right view Show Data &Editor Show data editor in right view Show &Title List Show title list in right view &Show Child Pane Toggle showing right-hand child views Toggle showing output view indented descendants &Close Window Close this window &File &Edit &Node &Data &Tools &View &Window &Help Start Incremental Search Next Incremental Search Previous Incremental Search Show &Breadcrumb View Toggle showing breadcrumb ancestor view Show Output &Descendants Fo&rmat colorset Dialog background color Dialog text color Text widget background color Text widget foreground color Selected item background color Selected item text color Link text color Tool tip background color Tool tip foreground color Button background color Button text color Disabled text foreground color Disabled button text color Color Settings Color Theme Default system theme Dark theme Custom theme &OK &Cancel Custom Colors Theme Colors Select {0} color TreeLine-3.2.1/working/translations/treeline_zh.ts000066400000000000000000005613031506556630100223240ustar00rootroot00000000000000 conditional starts with 以...开始 ends with 以...结尾 contains 包含 True False and or [All Types] [所有类型] Node Type 节点类型 &Add New Rule 添加新规则(&A) &Remove Rule 删除规则(&R) &OK 确认(&O) &Cancel 取消(&C) Find &Previous 查找上一个(&P) Find &Next 查找下一个(&N) &Filter 过滤(&F) &End Filter 结束过滤(&E) &Close 关闭(&C) No conditional matches were found 没有找到条件匹配 Rule {0} 规则{0} Saved Rules 保存规则 Name: 名字: &Load 载入(&L) &Save 保存(&S) &Delete 删除(&D) configdialog Configure Data Types 配置数据类型 T&ype List 类型列表(&y) Typ&e Config 类型配置(&e) Field &List 字段列表(&L) &Field Config 字段配置(&F) O&utput 输出(&u) &Show Advanced 显示高级(&S) &OK 确认(&O) &Apply 应用(&A) &Reset 重置(&R) &Cancel 取消(&C) &Hide Advanced 隐藏高级(&H) Error - circular reference in math field equations 错误 - 数学场方程中的循环引用 Add or Remove Data Types 添加或删除数据类型 &New Type... 新类型(&N)... Co&py Type... 拷贝类型(&p)... Rena&me Type... 重命名类型(&m)... &Delete Type 删除类型(&D) Add Type 添加类型 Enter new type name: 输入新类型的名字: Copy Type 复制类型 &Derive from original 从原来类型衍生(&D) Rename Type 重命名类型 Rename from {} to: 从{}重命名为: Cannot delete data type being used by nodes 无法删除节点使用的数据类型 [None] no type set [无] &Data Type 数据类型(&D) Default Child &Type 默认子节点类型(&T) Icon 图标 Change &Icon 改变图标(&I) Output Options 输出选项 Add &blank lines between nodes 在节点之间添加空行(&b) Allow &HTML rich text in format 允许&HTML多格式文本 Add text bullet&s 添加文本项目符号(&s) Use a table for field &data 为字段数据使用表格(&d) Combination && Child List Output &Separator 组合&&子列表输出分隔符(&S) Derived from &Generic Type 从通用类型衍生(&G) Automatic Types 自动类型 None Modify Co&nditional Types 修改条件类型(&n) Create Co&nditional Types 创建条件类型(&n) Set Types Conditionally 有条件地设置类型 Modify &Field List 修改字段列表(&F) Name 名字 Type 类型 Sort Key 排序键 Move U&p 上移(&p) Move Do&wn 下移(&w) &New Field... 新字段(&N)... Rena&me Field... 重命名字段(&m)... Dele&te Field 删除字段(&t) Sort &Keys... 排序键(&K)... fwd 正向 rev 逆向 Add Field 添加字段 Enter new field name: 输入新的字段名称: Rename Field 重命名字段 File Info Reference 文件信息参考 F&ield 字段(&i) &Field Type 字段类型(&F) Outpu&t Format 输出格式(&t) Format &Help 格式帮助(&H) Extra Text 额外文字 &Prefix 前缀(&P) Suffi&x 后缀(&x) Default &Value for New Nodes 新节点的缺省值(&V) Editor Height 编辑器高度 Num&ber of text lines 文本行数(&b) Math Equation 数学方程式 Define Equation 定义方程式 F&ield List 字段列表(&i) &Title Format 标题格式(&T) Out&put Format 输出格式(&p) Other Field References 其他字段参考 Reference Le&vel 参考级别(&v) Refere&nce Type 参考类型(&n) The name cannot be empty 名称不能为空 The name must start with a letter 名称必须以字母开头 The name cannot start with "xml" 名称不能以“xml”开头 The name cannot contain spaces 名称不能包含空格 The following characters are not allowed: {} 不允许使用以下字符:{} The name was already used 该名称已被使用 Set Data Type Icon 设置数据类型图标 Clear &Select 清除选择(&S) forward 正向 reverse 逆向 Sort Key Fields 排序关键字段 Available &Fields 可用字段(&F) &Sort Criteria 排序标准(&S) Field 字段 Direction 方向 Move &Up 上移(&U) &Move Down 下移(&M) Flip &Direction 翻转方向(&D) Self Reference 自引用 Parent Reference 父引用 Root Reference 根引用 Child Reference 子引用 Child Count 子计数 Date Result 日期结果 Time Result 时间结果 add subtract multiply divide floor divide 向下取整除 modulus 系数 power 乘方 sum of items 项目总和 maximum 最大 minimum 最小 average 平均 absolute value 绝对值 square root 平方根 natural logarithm 自然对数 base-10 logarithm 以10为底的对数 factorial 阶乘 round to num digits 四舍五入 lower integer 较低的整数(lower integer) higher integer 更高的整数(higher integer) truncated integer 截断的整数(truncated integer) floating point 浮点 sine of radians 正弦 cosine of radians 余弦 tangent of radians 切线(tangent of radians) arc sine 正弦波 arc cosine 反余弦 arc tangent 反正切 radians to degrees 弧度到度 degrees to radians 度数到弧度 pi constant π常数 natural log constant 自然对数常数 Define Math Field Equation 定义数学字段方程 Field References 字段引用 Reference &Level 引用级别(&L) Reference &Type 引用类型(&T) Available &Field List 可用字段列表(&F) &Result Type 结果类型(&R) Description 描述 &Equation 方程式(&E) Equation error: {} 方程式错误:{} Boolean Result 布尔结果 Text Result 文本结果 Arithmetic Operators 算术运算符 Comparison Operators 比较运算符 Text Operators 文本运算符 equal to 等于 less than 小于 greater than 大于 less than or equal to 小于等于 greater than or equal to 大于等于 not equal to 不等 true value, condition, false value 真值, 条件, 假值 true if 1st text arg starts with 2nd arg 如果第一个文本参数以第二个参数开头,则为真 true if 1st text arg ends with 2nd arg 如果第一个文本参数以第二个参数结尾,则为真 true if 1st text arg contains 2nd arg 如果第一个文本参数包含第二个参数,则为真 concatenate text 连接文本 join text using 1st arg as separator 使用第一个参数作为分隔符连接文本 convert text to upper case 将文本转换为大写 convert text to lower case 将文本转换为小写 in 1st arg, replace 2nd arg with 3rd arg 在第一个参数中,将第二个参数替换为第三个参数 Operations 运算 O&perator Type 运算类型(&p) Oper&ator List 运算列表(&a) logical and 逻辑与 logical or 逻辑或 Output HTML 输出HTML Evaluate &HTML tags 评估&HTML标记 Child Type Limits 子类型限制 [All Types Available] [所有可用类型] &Select All 选择所有(&S) Select &None 都不选(&N) Number Result 数字结果 Count 计数 Number of Children 子节点数量 dataeditors Today's &Date 当前日期(&D) &Open Link 打开链接(&O) Open &Folder 打开文件夹(&F) External Link 外部链接 Scheme 方案 &Browse for File 浏览文件(&B) File Path Type 文件路径类型 Absolute 绝对 Relative 相对 Address 地址 Display Name 显示名称 &OK 确认(&O) &Cancel 取消(&C) TreeLine - External Link File TreeLine - 外部链接文件 &Go to Target 转到目标(&G) Internal Link 内部链接 &Open Picture 打开图片(&O) Picture Link 图片链接 TreeLine - Picture File TreeLine - 图片文件 Set to &Now 设置为当前时间(&N) Clear &Link 清除链接(&L) (Click link target in tree) (在树中点击链接目标) link 链接 exports Bookmarks 书签 TreeLine - Export HTML TreeLine - 导出HTML TreeLine - Export Text Titles TreeLine - 导出文本标题 TreeLine - Export Plain Text TreeLine - 导出纯文本 TreeLine - Export Text Tables TreeLine - 导出文本表格 TreeLine - Export Generic XML TreeLine - 导出通用XML TreeLine - Export TreeLine Subtree TreeLine - 导出TreeLine子树 TreeLine - Export ODF Text TreeLine - 导出ODF文本 TreeLine - Export HTML Bookmarks TreeLine - 导出HTML书签 TreeLine - Export XBEL Bookmarks TreeLine - 导出XBEL书签 &HTML &HTML &Text 文本(&T) &ODF Outline &ODF大纲 Book&marks 书签(&m) &Single HTML page 单个HTML页面(&S) Single &HTML page with navigation pane 带有导航窗格的单个&HTML页面 Multiple HTML &pages with navigation pane 带导航窗格的多个HTML页面(&p) Multiple HTML &data tables 多个HTML和数据表(&d) &Tabbed title text 标签标题文字(&T) &Unformatted output of all text 未格式化的所有文本输出(&U) &HTML format bookmarks &HTML格式的书签 &XBEL format bookmarks &XBEL格式的书签 File Export 文件导出 Choose export format type 选择导出格式类型 Choose export format subtype 选择导出格式子类型 Choose export options 选择导出选项 What to Export 导出什么 &Entire tree 整棵树(&E) Selected &branches 选定的分支(&b) Selected &nodes 选定的节点(&n) Other Options 其他选项 &Only open node children 只有打开节点的子节点(&O) Include &print header && footer 包括打印标题和页脚(&p) &Columns 列(&C) Navigation pane &levels 导航窗格级别(&l) Error - export template files not found. Check your TreeLine installation. 错误 - 未找到导出模板文件。 检查TreeLine安装。 Error - cannot link to unsaved TreeLine file. Save the file and retry. 错误 - 无法链接到未保存的TreeLine文件。 保存文件并重试。 Warning - no relative path from "{0}" to "{1}". Continue with absolute path? 警告 - 没有从“{0}”到“{1}”的相对路径。 继续绝对路径? Parent Tree&Line Tree&Line &XML (generic) &XML (通用) Live tree view, linked to TreeLine file (for web server) 实时树视图,链接到TreeLine文件(用于Web服务器) Live tree view, single file (embedded data) 实时树视图,单个文件(嵌入数据) &Comma delimited (CSV) table of descendants (level numbers) 逗号分隔(CSV)后代表格(级别编号)(&C) Comma &delimited (CSV) table of children (single level) 逗号分隔(CSV)子表格(单级)(&d) Tab &delimited table of children (&single level) 制表符分隔(CSV)子表格(单级)(&d) &Old TreeLine (2.0.x) 老版本TreeLine (2.0.x)(&O) &TreeLine Subtree TreeLine子树(&T) &Include root nodes 包括根节点(&I) Must select nodes prior to export 必须在导出之前选择节点 fieldformat Text 文本 HtmlText Html文本 OneLineText 单行文本 SpacedText 间隔文本 Number 数字 Math 数学 Numbering 编号 Boolean 布尔 Date 日期 Time 时间 Choice 选择 AutoChoice 自动选择 Combination 组合 AutoCombination 自动组合 ExternalLink 外部链接 InternalLink 内部链接 Picture 图片 RegularExpression 正则表达式 Now 现在 Optional Digit # 可选数字 # Required Digit 0 必需数字 0 Digit or Space (external) <space> 数字或空格(外部) <space> Decimal Point . 小数点 . Decimal Comma , 十进制逗号 , Space Separator (internal) <space> 空格分隔符 (内部) <space> Optional Sign - 可选标志 - Required Sign + 必需的标志 + Exponent (capital) E 指数 (大写) E Exponent (small) e 指数(小写) e Number 1 数 1 Capital Letter A 大写字母 A Small Letter a 小写字母 a Capital Roman Numeral I 大写罗马数字 I Small Roman Numeral i 小写罗马数字 i Level Separator / 级分隔符 / Section Separator . 段落分隔符 . "/" Character // "/" 字符 // "." Character .. "." 字符 .. Outline Example I../A../1../a)/i) 大纲例子 I../A../1../a)/i) Section Example 1.1.1.1 段落例子 1.1.1.1 Separator / 分隔符 / Example 1/2/3/4 例子 1/2/3/4 yes/no yes/no true/false true/false T/F T/F Y/N Y/N Any Character . 任意字符 . End of Text $ 文本结尾 $ 0 Or More Repetitions * 重复0或多次 * 1 Or More Repetitions + 重复1或多次 + 0 Or 1 Repetitions ? 重复0或1次 ? Set of Numbers [0-9] 数字 [0-9] Lower Case Letters [a-z] 小写字母 [a-z] Upper Case Letters [A-Z] 大写字母 [A-Z] Not a Number [^0-9] 非数字 [^0-9] Or | 或 | Escape a Special Character \ 特殊字符转义 \ DateTime 日期时间 Day (1 or 2 digits) %-d 日 (1或2位) %-d Day (2 digits) %d 日 (2位) %d Weekday Abbreviation %a 星期缩写 %a Weekday Name %A 星期名字 %A Month (1 or 2 digits) %-m 月 (1 or 2 digits) %-m Month (2 digits) %m 月 (2 digits) %m Month Abbreviation %b 月缩写 %b Month Name %B 月名字 %B Year (2 digits) %y 年 (2 digits) %y Year (4 digits) %Y 年 (4 digits) %Y Week Number (0 to 53) %-U 星期数字 (0 to 53) %-U Day of year (1 to 366) %-j 年内第几日 (1 to 366) %-j Hour (0-23, 1 or 2 digits) %-H 小时(0-23, 1 or 2 digits) %-H Hour (00-23, 2 digits) %H 小时(00-23, 2 digits) %H Hour (1-12, 1 or 2 digits) %-I 小时 (1-12, 1 or 2 digits) %-I Hour (01-12, 2 digits) %I 小时 (01-12, 2 digits) %I Minute (1 or 2 digits) %-M 分 (1 or 2 digits) %-M Minute (2 digits) %M 分 (2 digits) %M Second (1 or 2 digits) %-S 秒 (1 or 2 digits) %-S Second (2 digits) %S 秒 (2 digits) %S Microseconds (6 digits) %f 毫秒 (6 digits) %f AM/PM %p AM/PM %p Comma Separator \, 逗号分隔符 \, Dot Separator \. 点分隔符 \. DescendantCount 后代数 genboolean true false yes no globalref TreeLine Files TreeLine文件 TreeLine Files - Compressed TreeLine文件 - 压缩 TreeLine Files - Encrypted TreeLine文件 - 加密 All Files 所有文件 HTML Files HTML文件 Text Files 文本文件 XML Files XML文件 ODF Text Files ODF文本文件 Treepad Files Treepad文件 PDF Files PDF文件 CSV (Comma Delimited) Files CSV(逗号分隔)文件 All TreeLine Files 所有TreeLine文件 Old TreeLine Files 老TreeLine文件 helpview Tools 工具 &Back 返回(&B) &Forward 前进(&F) &Home 主页(&H) Find: 查找: Find &Previous 查找前一个(&P) Find &Next 查找后一个(&N) Text string not found 没找到文本串 imports &Tab indented text, one node per line &Tab缩进文本,每行一个节点 Tab delimited text table with header &row 带标题和行的Tab分隔文本表格(&r) Plain text &paragraphs (blank line delimited) 纯文本与段落(空白行分隔)(&p) Treepad &file (text nodes only) Treepad文件(仅限文本节点)(&f) &Generic XML (non-TreeLine file) 通用XML(非TreeLine文件)(&G) Open &Document (ODF) outline Open &Document (ODF)大纲 &HTML bookmarks (Mozilla Format) &HTML书签(Mozilla格式) &XML bookmarks (XBEL format) &XML书签(XBEL格式) FOLDER 目录 BOOKMARK 书签 SEPARATOR 分隔符 Link 链接 Text 文本 Import File 导入文件 Choose Import Method 选择导入方式 Invalid File 无效的文件 "{0}" is not a valid TreeLine file. Use an import filter? "{0}"不是有效的TreeLine文件。 使用导入过滤器? TreeLine - Import File TreeLine - 导入文件 Error - could not read file {0} 错误 - 无法读取文件{0} Error - improper format in {0} 错误 - {0}中的格式不正确 TABLE 表格 Bookmarks 书签 Too many entries on Line {0} 行{0}上的条目太多 Plain text, one &node per line (CR delimited) 纯文本,每行一个节点(回车分隔)(&n) Bad CSV format on Line {0} 行{0}上的错误CSV格式 Co&mma delimited (CSV) text table with level column && header row 带有级别列 && 标题行的逗号分隔(CSV)文本表格(&m) Comma delimited (CSV) text table &with header row 带有标题行的逗号分隔(CSV)文本表格(&w) Other 其他 Old Tree&Line File (1.x or 2.x) 老版本Tree&Line文件(1.x或2.x) Invalid level number on line {0} 第{0}行上的级别编号无效 Invalid level structure 级别结构无效 No headings found matheval Illegal "{}" characters 非法的"{}"字符 Child references must be combined in a function 必须在函数中组合子引用 Illegal syntax in equation 等式中的非法语法 Illegal function present: {0} 存在非法函数: {0} Illegal object type or operator: {0} 非法对象类型或运算符: {0} Invalid field modifiers miscdialogs &OK 确认(&O) &Cancel 取消(&C) Fields 字段 File Properties 文件属性 File Storage 文件存储 &Use file compression 使用文件压缩(&U) Use file &encryption 使用文件加密(&e) Spell Check 拼写检查 Language code or dictionary (optional) 语言代码或 字典(可选) Math Fields 数学字段 &Treat blank fields as zeros 将空白字段视为零(&T) Encrypted File Password 加密文件密码 Type Password for "{0}": 输入“{0}”的密码: Type Password: 输入密码: Re-Type Password: 重新输入密码: Remember password during this session 在此会话期间记住密码 Zero-length passwords are not permitted 不允许使用零长度密码 Re-typed password did not match 重新输入的密码不匹配 Default - Single Line Text 默认 - 单行文字 &Search Text 搜索文字(&S) What to Search 搜索内容 Full &data 完整数据(&d) &Titles only 只有标题(&T) How to Search 如何搜索 &Key words 关键词(&K) Key full &words 完整的关键词(&w) F&ull phrase 完整的短语(&u) &Regular expression 正则表达式(&R) Find 查找 Find &Previous 查找上一个(&P) Find &Next 查找下一个(&N) Filter 过滤 &Filter 过滤(&F) &End Filter 结束过滤(&E) &Close 关闭(&C) Error - invalid regular expression 错误 - 无效的正则表达式 Search string "{0}" not found 搜索字符串“{0}”未找到 Find and Replace 查找和替换 Replacement &Text 替换文字(&T) Any &match 任意匹配(&m) Full &words 完整的词(&w) Re&gular expression 正则表达式(&g) &Node Type 节点类型(&N) N&ode Fields 节点字段(&o) &Find Next 查找下一个(&F) &Replace 替换(&R) Replace &All 替换全部(&A) [All Types] [所有类型] [All Fields] [所有字段] Search text "{0}" not found 搜索文本“{0}”未找到 Error - replacement failed 错误 - 替换失败 Replaced {0} matches 替换了{0}个匹配项 Sort Nodes 节点排序 What to Sort 排序内容 &Entire tree 整棵树(&E) Selected &branches 选定的分支(&b) Selection's childre&n 选择节点的子节点(&n) Selection's &siblings 选择节点的同级节点(&s) Sort Method 排序方法 &Predefined Key Fields 预定义的关键字段(&P) Node &Titles 节点标题(&T) Sort Direction 排序方向 &Forward 正向(&F) &Reverse 反向(&R) &Apply 应用(&A) Update Node Numbering 更新节点编号 What to Update 更新的内容 &Selection's children 选择节点的子节点(&S) Root Node 根节点 Include top-level nodes 包括顶级节点 Handling Nodes without Numbering Fields 处理没有编号字段的节点 &Ignore and skip 忽略并跳过(&I) &Restart numbers for next siblings 重启下一个同级节点的编号(&R) Reserve &numbers 保留的编号(&n) TreeLine Numbering TreeLine编号 No numbering fields were found in data types 在数据类型中找不到编号字段 File Menu 文件菜单 File 文件 Edit Menu 编辑菜单 Edit 编辑 Node Menu 节点菜单 Node 节点 Data Menu 数据菜单 Data 数据 Tools Menu 工具菜单 Tools 工具 View Menu 视图菜单 View 视图 Window Menu 窗口菜单 Window 窗口 Help Menu 帮助菜单 Help 帮助 Keyboard Shortcuts 键盘快捷键 &Restore Defaults 恢复默认(&R) Key {0} is already used 键{0}已被使用 Clear &Key 清除键(&K) --Separator-- - 分隔符 - Customize Toolbars 自定义工具栏 Toolbar &Size 工具栏尺寸(&S) Small Icons 小图标 Large Icons 大图标 Toolbar Quantity 工具栏数量 &Toolbars 工具栏(&T) A&vailable Commands 可用命令(&v) Tool&bar Commands 工具栏命令(&b) Move &Up 上移(&U) Move &Down 下移(&D) Tree View Font 树视图字体 Output View Font 输出视图字体 Editor View Font 编辑器视图字体 No menu 无菜单 TreeLine - Serious Error TreeLine - 严重错误 A serious error has occurred. TreeLine could be in an unstable state. Recommend saving any file changes under another filename and restart TreeLine. The debugging info shown below can be copied and emailed to doug101@bellz.org along with an explanation of the circumstances. 发生了严重错误。 TreeLine可能处于不稳定状态. 建议在另一个文件名下保存任何文件更改并重新启动TreeLine. 下面显示的调试信息可以复制并通过电子邮件发送到doug101@bellz.org 对情况的解释. Format Menu 格式菜单 Format 格式 Customize Fonts 自定义字体 &Use system default font 使用系统默认字体(&U) App Default Font 应用默认字体 &Use app default font 使用应用默认字体(&U) Externally Modified File &Overwrite File &Cancel Save File was externally modified at {} nodeformat Name 名字 optiondefaults Monday 星期一 Tuesday 星期二 Wednesday 星期三 Thursday 星期四 Friday 星期五 Saturday 星期六 Sunday 星期日 Startup Condition 启动条件 Automatically open last file used 自动打开上次使用的文件 Show descendants in output view 在输出视图中显示后代 Restore tree view states of recent files 恢复最近文件的树视图状态 Restore previous window geometry 恢复上一个窗口几何 Features Available 可用功能 Open files in new windows 在新窗口中打开文件 Click node to rename 单击节点重命名 Rename new nodes when created 创建时重命名新节点 Tree drag && drop available 树拖放可用 Show icons in the tree view 在树视图中显示图标 Show math fields in the Data Edit view 在数据编辑视图中显示数学字段 Show numbering fields in the Data Edit view 在数据编辑视图中显示编号字段 Undo Memory 撤消内存 Number of undo levels 撤消级别数 Auto Save 自动保存 Minutes between saves (set to 0 to disable) 保存之间的分钟数 (设为0表示禁用) Recent Files 最近的文件 Number of recent files in the file menu 最近文件的数量 在文件菜单中 Data Editor Formats 数据编辑器格式 Times Dates 日期 First day of week 第一天 每周 Appearance 呈现 Child indent offset (in font height units) 子缩进偏移 (字体高度单位) Show breadcrumb ancestor view 显示面包屑祖先视图 Show child pane in right hand views 在右手视图中显示子窗格 Remove inaccessible recent file entries 删除无法访问的最近文件条目 Activate data editors on mouse hover 在鼠标悬停时激活数据编辑器 Minimize application to system tray 最小化应用程序到系统托盘 Indent (pretty print) TreeLine JSON files 缩进(优雅打印)TreeLine JSON文件 Limit data editor height to window size options Choose configuration file location 选择配置文件位置 User's home directory (recommended) 用户的主目录(推荐) Program directory (for portable use) 程序目录(便携式使用) &OK 确认(&O) &Cancel 取消(&C) printdata Error initializing printer 初始化打印机时出错 TreeLine - Export PDF TreeLine - 导出PDF Warning: Page size and margin settings unsupported on current printer. Save page adjustments? 警告:当前打印机不支持页面大小和边距设置。 保存页面调整? Warning: Page size setting unsupported on current printer. Save adjustment? 警告:当前打印机不支持页面大小设置。 保存调整? Warning: Margin settings unsupported on current printer. Save adjustments? 警告:当前打印机不支持边距设置。 保存调整? printdialogs Print Preview 打印预览 Fit Width 适合宽度 Fit Page 适合页面 Zoom In 放大 Zoom Out 缩小 Previous Page 前一页 Next Page 后一页 Single Page 单页 Facing Pages 面对页面 Print Setup 打印设置 Print 打印 Printing Setup 打印设置 &General Options 常规选项(&G) Page &Setup 页面设置(&S) &Font Selection 字体选择(&F) &Header/Footer 页眉/页脚(&H) Print Pre&view... 打印预览(&v)... &Print... 打印(&P)... &OK 确认(&O) &Cancel 取消(&C) What to print 打印什么 &Entire tree 整棵树(&E) Selected &branches 选定的分支(&b) Selected &nodes 选定的节点(&n) Included Nodes 包括的节点 &Include root node 包括根节点(&I) Onl&y open node children 只有打开节点的子节点(&y) Features 特征 &Draw lines to children 给子节点画线(&D) &Keep first child with parent 保持第一个子节点在父节点上(&K) Indent 缩进 Indent Offse&t (line height units) 缩进偏移量(&t) (线高单位) Letter (8.5 x 11 in.) 信纸 (8.5 x 11 in.) Legal (8.5 x 14 in.) 法律文书 (8.5 x 14 in.) Tabloid (11 x 17 in.) 小型报纸 (11 x 17 in.) A3 (279 x 420 mm) A3 (279 x 420 mm) A4 (210 x 297 mm) A4 (210 x 297 mm) A5 (148 x 210 mm) A5 (148 x 210 mm) Custom Size 自定义大小 Inches (in) 英寸(in) Millimeters (mm) 毫米 (mm) Centimeters (cm) 厘米 (cm) &Units 单位(&U) Paper &Size 纸张尺寸(&S) &Width: 宽(&W): Height: 高: Orientation 方向 Portra&it 竖向(&i) Lan&dscape 水平(&d) Margins 边距 &Left: 左(&L): &Top: 上(&T): &Right: 右(&R): &Bottom: 下(&B): He&ader: 页眉(&a): Foot&er: 页脚(&e): Columns &Number of columns 列数(&N) Space between colu&mns 列之间空格(&m) Default Font 默认字体 &Use TreeLine output view font 使用TreeLine输出视图字体(&U) Select Font 选择字体 &Font 字体(&F) Font st&yle 字体样式(&y) Si&ze 尺寸(&z) Sample 示例 AaBbCcDdEeFfGg...TtUuVvWvXxYyZz AaBbCcDdEeFfGg...TtUuVvWvXxYyZz &Header Left 页眉左(&H) Header C&enter 页眉中(&e) Header &Right 页眉右(&R) Footer &Left 页脚左(&L) Footer Ce&nter 页脚中(&n) Footer Righ&t 页脚右(&t) Fiel&ds 字段(&d) Field For&mat 字段格式(&m) Header and Footer 页眉和页脚 Field Format for "{0}" "{0}"的字段格式 Output &Format 输出格式(&F) Format &Help 格式帮助(&H) Extra Text 额外文字 &Prefix 前缀(&P) &Suffix 后缀(&S) Error: Page size or margins are invalid 错误:页面大小或边距无效 TreeLine PDF Printer TreeLine PDF 打印机 Select &Printer 选择打印机(&P) spellcheck Could not find either aspell.exe, ispell.exe or hunspell.exe Browse for location? 找不到aspell.exe,ispell.exe或hunspell.exe 指定位置? Spell Check Error 拼写检查错误 Locate aspell.exe, ipsell.exe or hunspell.exe 定位aspell.exe,ipsell.exe或hunspell.exe Program (*.exe) 程序(*.exe) TreeLine Spell Check Error Make sure aspell, ispell or hunspell is installed TreeLine拼写检查错误 确保安装了aspell,ispell或hunspell TreeLine Spell Check TreeLine拼写检查 Finished spell checking 完成拼写检查 Spell Check 拼写检查 Not in Dictionary 不在字典中 Word: 词: Context: 上下文: Suggestions 建议 Ignor&e 忽略(&e) &Ignore All 忽略全部(&I) &Add 添加(&A) Add &Lowercase 添加小写(&L) &Replace 替换(&R) Re&place All 替换全部(&p) &Cancel 取消(&C) Finished checking the branch Continue from the top? 完成检查分支 从顶部继续? titlelistview Select in Tree 在树中选择 treeformats DEFAULT 默认 FILE 文件 TYPE 类型 FIELD 字段 FieldType 字段类型 TitleFormat 标题格式 OutputFormat 输出格式 SpaceBetween 中间空格 FormatHtml 格式Html Bullets 项目符号 Table 表格 ChildType 子类型 Icon 图标 GenericType 一般类型 ConditionalRule 条件规则 ListSeparator 列表分割符 ChildTypeLimit 子类型限制 Format 格式 Prefix 前缀 Suffix 后缀 InitialValue 初始值 NumLines 数字线 SortKeyNum 排序键编号 SortForward 向前排序 EvalHtml 评估Html treelocalcontrol Error - could not delete backup file {} 错误 - 无法删除备份文件{} Save changes to {}? 将更改保存到{}? Save changes? 保存更改? &Save 保存(&S) Save File 保存文件 Save the current file 保存当前文件 Save &As... 另存为(&A)... Save the file with a new name 使用新名称保存文件 &Export... 导出(&E)... Export the file in various other formats 以各种其他格式导出文件 Prop&erties... 属性(&e)... Set file parameters like compression and encryption 设置压缩和加密等文件参数 P&rint Setup... 打印设置(&r)... Set margins, page size and other printing options 设置边距,页面大小和其他打印选项 Print Pre&view... 打印预览(&v)... Show a preview of printing results 显示打印结果的预览 &Print... 打印(&P)... Print tree output based on current options 根据当前选项打印树输出 Print &to PDF... 打印到PDF(&t)... Export to PDF with current printing options 使用当前打印选项导出为PDF &Undo 撤消(&U) Undo the previous action 撤消上一个操作 &Redo 重做(&R) Redo the previous undo 重做上一个撤消 Cu&t 剪切(&t) Cut the branch or text to the clipboard 将分支或文本剪切到剪贴板 &Copy 拷贝(&C) Copy the branch or text to the clipboard 将分支或文本复制到剪贴板 &Paste 粘贴(&P) Paste nodes or text from the clipboard 粘贴剪贴板中的节点或文本 Paste non-formatted text from the clipboard 从剪贴板粘贴未格式化的文本 &Bold Font 粗体(&B) Set the current or selected font to bold 将当前或选定的字体设置为粗体 &Italic Font 斜体(&I) Set the current or selected font to italic 将当前或选定的字体设置为斜体 U&nderline Font 下划线(&n) Set the current or selected font to underline 将当前或选定的字体设置为下划线 &Font Size 字体大小(&F) Set size of the current or selected text 设置当前或所选文本的大小 Small Default 默认 Large Larger 更大 Largest 最大 Set Font Size 设置字体大小 Font C&olor... 字体颜色(&o)... Set the color of the current or selected text 设置当前或所选文本的颜色 &External Link... 外部链接(&E)... Add or modify an extrnal web link 添加或修改外部Web链接 Internal &Link... 内部链接(&L)... Add or modify an internal node link 添加或修改内部节点链接 Clear For&matting 清除格式(&m) Clear current or selected text formatting 清除当前或选定的文本格式 &Rename 重命名(&R) Rename the current tree entry title 重命名当前树条目标题 Insert Sibling &Before 之前插入同级(&B) Insert new sibling before selection 在选择节点之前插入新的同级节点 Insert Sibling &After 之后插入同级(&A) Insert new sibling after selection 在选择节点之后插入新的同级节点 Add &Child 添加子节点(&C) Add new child to selected parent 将新子项添加到选定的父项 &Delete Node 删除节点(&D) Delete the selected nodes 删除所选节点 &Indent Node 缩进节点(&I) Indent the selected nodes 缩进选定的节点 &Unindent Node 取消缩进节点(&U) Unindent the selected nodes 取消缩进选定的节点 &Move Up 上移(&M) Move the selected nodes up 上移选定的节点 M&ove Down 下移(&o) Move the selected nodes down 下移选定的节点 Move &First 移到首位(&F) Move the selected nodes to be the first children 将所选节点移动为第一个子节点 Move &Last 移到最后(&L) Move the selected nodes to be the last children 将所选节点移动为最后一个子节点 &Set Node Type 设置节点类型(&S) Set the node type for selected nodes 设置所选节点的节点类型 Set Node Type 设置节点类型 Copy Types from &File... 从文件复制类型(&F)... Copy the configuration from another TreeLine file 从另一个TreeLine文件复制配置 Flatten &by Category 按类别拼合(&b) Collapse descendants by merging fields 通过合并字段折叠后代 Add Category &Level... 添加类别级别(&L)... Insert category nodes above children 在子项上方插入类别节点 &Spell Check... 拼写检查(&S)... &New Window 新建窗口(&N) Open a new window for the same file 打开同一文件的新窗口 Error - could not write to {} 错误 - 无法写入{} TreeLine - Save As TreeLine - 另存为 Error - could not write to file 错误 - 无法写入文件 TreeLine - Open Configuration File TreeLine - 打开配置文件 Error - could not read file {0} 错误 - 无法读取文件{0} Cannot expand without common fields 没有常见字段无法扩展 Category Fields 类别字段 Select fields for new level 选择新级别的字段 File saved 文件已保存 Pa&ste Plain Text 粘贴纯文本(&s) Paste C&hild 粘贴子节点(&h) Paste a child node from the clipboard 从剪贴板粘贴子节点 Paste Sibling &Before 之前粘贴同级(&B) Paste a sibling before selection 在选择节点之前粘贴新的同级节点 Paste Sibling &After 之后粘贴同级(&A) Paste a sibling after selection 在选择节点之后粘贴新的同级节点 Paste Cl&oned Child 粘贴克隆的子节点(&o) Paste a child clone from the clipboard 从剪贴板粘贴克隆的子节点 Paste Clo&ned Sibling Before 之前粘贴克隆的同级(&n) Paste a sibling clone before selection 在选择节点之前粘贴新的同级克隆节点 Paste Clone&d Sibling After 之后粘贴克隆的同级(&d) Paste a sibling clone after selection 在选择节点之后粘贴新的同级克隆节点 Clone All &Matched Nodes 克隆所有匹配的节点(&M) Convert all matching nodes into clones 将所有匹配的节点转换为克隆 &Detach Clones 分离克隆(&D) Detach all cloned nodes in current branches 分离当前分支中的所有克隆节点 S&wap Category Levels 交换类别级别(&w) Swap child and grandchild category nodes 交换子节点和孙节点类节点 Converted {0} branches into clones 将{0}分支转换为克隆 No identical nodes found 找不到相同的节点 Warning - file corruption! Skipped bad child references in the following nodes: 警告 - 文件损坏! 在以下节点中跳过了坏子引用: Spell check the tree's text data 拼写检查树的文本数据 &Regenerate References 重新生成参考(&R) Force update of all conditional types & math fields 强制更新所有条件类型和数学字段 Insert &Date Insert current date as text St&rikethrough Font Set the current or selected font to strikethough treemaincontrol Warning: Could not create local socket 警告:无法创建本地套接字 Error - could not write config file to {} 错误 - 无法将配置文件写入{} Error - could not read file {0} 错误 - 无法读取文件{0} Backup file "{}" exists. A previous session may have crashed 备份文件“{}”存在。 之前的会话可能已经崩溃 &Restore Backup 恢复备份(&R) &Delete Backup 删除备份(&D) &Cancel File Open 取消文件打开(&C) Error - could not rename "{0}" to "{1}" 错误 - 无法将“{0}”重命名为“{1}” Error - could not remove backup file {} 错误 - 无法删除备份文件{} &New... 新建(&N)... New File 新文件 Start a new file 开始一个新文件 &Open... 打开(&O)... Open File 打开文件 Open a file from disk 从磁盘上打开文件 Open Sa&mple... 打开示例文件(&m)... Open Sample 打开示例文件 Open a sample file 打开一个示例文件 &Import... 导入(&I)... Open a non-TreeLine file 打开一个非TreeLine文件 &Quit 退出(&Q) Exit the application 退出应用 &Select All 选择所有(&S) Select all text in an editor 在编辑器里选择所有 &Configure Data Types... 配置数据类型(&C)... Modify data types, fields & output lines 编辑数据类型,字段和输出行 Sor&t Nodes... 节点排序(&t)... Define node sort operations 定义节点排序操作 Update &Numbering... 更新编号(&N)... Update node numbering fields 更新节点数值型字段 &Find Text... 查找文本(&F)... Find text in node titles & data 在标题和数据中查找文本 &Conditional Find... 条件查找(&C)... Use field conditions to find nodes 使用字段条件查找节点 Find and &Replace... 查找和替换(&R)... Replace text strings in node data 替换节点数据中的文本字符串 &Text Filter... 文本过滤器(&T)... Filter nodes to only show text matches 过滤节点仅显示匹配文本 C&onditional Filter... 条件过滤器(&o)... Use field conditions to filter nodes 使用字段条件过滤节点 &General Options... 常规选项(&G)... Set user preferences for all files 设置所有文件的用户首选项 Set &Keyboard Shortcuts... 设置键盘快捷键(&K)... Customize keyboard commands 自定义键盘命令 C&ustomize Toolbars... 自定义工具栏(&u)... Customize toolbar buttons 自定义工具栏按钮 Customize Fo&nts... 自定义字体(&n)... Customize fonts in various views 在各种视图中自定义字体 &Basic Usage... 基本用法(&B)... Display basic usage instructions 显示基本使用说明 &Full Documentation... 完整文档(&F)... Open a TreeLine file with full documentation 使用完整文档打开TreeLine文件 &About TreeLine... 关于TreeLine(&A)... Display version info about this program 显示有关此程序的版本信息 &Select Template 选择模板(&S) TreeLine - Open File TreeLine - 打开文件 Open Sample File 打开一个示例文件 &Select Sample 选择示例文件(&S) Conditional Find 条件查找 Conditional Filter 条件过滤器 General Options 常规选项 Error - basic help file not found 错误 - 找不到基本帮助文件 TreeLine Basic Usage TreeLine基本用法 Error - documentation file not found 错误 - 找不到文档文件 Error - invalid TreeLine file {0} 错误 - 无效的TreeLine文件{0} TreeLine version {0} TreeLine版本{0} written by {0} 由{0}编写 Library versions: 库版本: missing directory 缺少目录 Show C&onfiguration Structure... 显示配置结构(&o)... Show read-only visualization of type structure 显示只读的类型结构可视化 Custo&mize Colors... Customize GUI colors and themes treenode New 新建 treestructure Main treeview Filtering by "{0}", found {1} nodes 按"{0}"过滤,找到{1}个节点 Conditional filtering, found {0} nodes 条件过滤,找到{0}个节点 Search for: 搜索: Search for: {0} 搜索: {0} Search for: {0} (not found) 搜索: {0} (未找到) Next: {0} 下一个: {0} Next: {0} (not found) 下一个: {0} (未找到) treewindow Data Output 数据输出 Data Edit 数据编辑 Title List 标题列表 &Expand Full Branch 展开完整分支(&E) Expand all children of the selected nodes 展开选定节点的所有子节点 &Collapse Full Branch 折叠完整分支(&C) Collapse all children of the selected nodes 折叠选定节点的所有子节点 &Previous Selection 上一个选则(&P) Return to the previous tree selection 返回上一个树选择 &Next Selection 下一个选择(&N) Go to the next tree selection in history 去到下一个历史树选择 Show Data &Output 显示数据输出(&O) Show data output in right view 在右侧视图显示数据输出 Show Data &Editor 显示数据编辑器(&E) Show data editor in right view 在右侧视图显示数据编辑器 Show &Title List 显示标题列表(&T) Show title list in right view 在右侧视图显示标题列表 &Show Child Pane 显示子窗格(&S) Toggle showing right-hand child views 切换显示右侧子视图 Toggle showing output view indented descendants 切换显示输出视图缩进后代 &Close Window 关闭窗口(&C) Close this window 关闭这个窗口 &File 文件(&F) &Edit 编辑(&E) &Node 节点(&N) &Data 数据(&D) &Tools 工具(&T) &View 视图(&V) &Window 窗口(&W) &Help 帮助(&H) Start Incremental Search 开始增量搜索 Next Incremental Search 下一个增量搜索 Previous Incremental Search 上一个增量搜索 Show &Breadcrumb View 显示面包屑视图(&B) Toggle showing breadcrumb ancestor view 切换显示面包屑祖视图 Show Output &Descendants 显示输出后代(&D) Fo&rmat 格式(&r) colorset Dialog background color Dialog text color Text widget background color Text widget foreground color Selected item background color Selected item text color Link text color Tool tip background color Tool tip foreground color Button background color Button text color Disabled text foreground color Disabled button text color Color Settings Color Theme 色彩主题 Default system theme Dark theme Custom theme &OK 确认(&O) &Cancel 取消(&C) Custom Colors Theme Colors Select {0} color