| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| |
| = FolderOrdering103187 |
| :page-layout: wiki |
| :page-tags: wiki, devfaq, needsreview |
| :markup-in-source: verbatim,quotes,macros |
| :jbake-status: published |
| :page-syntax: true |
| :description: Folder Ordering using Numeric Sort |
| :icons: font |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :experimental: |
| |
| Folder ordering using numeric sort. |
| |
| [[Infrastructure]] |
| == Infrastructure |
| |
| *merged to trunk* (Jun 16 2007) |
| link:http://deadlock.netbeans.org/fisheye/changelog/netbeans/?cs=MAIN:jglick:20070616100742[changeset] |
| link:https://bz.apache.org/netbeans/show_bug.cgi?id=103187[Issue #103187] |
| link:http://deadlock.netbeans.org/hudson/job/trunk/lastSuccessfulBuild/artifact/nbbuild/build/generated/layers.txt[Current SFS with positions] |
| |
| |
| [[Overview]] |
| == Overview |
| |
| |
| [[Previous_state]] |
| === Previous state |
| |
| The Filesystems API specifies no order in folder children (`FileObject.getChildren`). |
| But the Datasystems API does assign a meaning to the order of `DataFolder.getChildren`. |
| Currently there are four ways a folder may get an order: |
| |
| 1. If the folder attribute `OpenIDE-Folder-Order` is specified, it is used. |
| (Any children not mentioned are put at the end.) |
| The format is `a/b/c` where `a` etc. are file or subfolder names. |
| `DataFolder.setOrder` sets this attribute. |
| |
| . If the folder attribute `OpenIDE-Folder-SortMode` is specified, it is used. |
| The format is a single character, e.g. `M` for sort by modification time. |
| This method is hardly used any more, although the sort mode attribute is still shown |
| in the property sheet for folder nodes. |
| |
| . If there are some relative ordering attributes, the folder is topologically sorted. |
| The attribute `a/b`, if set to the value `Boolean.TRUE`, means that |
| `a` should come somewhere before `b` in the folder |
| (not necessarily immediately before). |
| |
| . Otherwise, the fallback order is alphabetical (same as `OpenIDE-Folder-SortMode=F`). |
| |
| NOTE: although these methods can apply to any folder, in practice only folders on |
| the system filesystem, i.e. defined in XML layers, are explicitly ordered. |
| |
| |
| [[Problems_with_current_state]] |
| === Problems with current state |
| |
| The third way is the only one suitable for a modular system. |
| It has been in use since NetBeans 3.1. |
| Unfortunately it suffers from several drawbacks: |
| |
| 1. New developers are confused by ordering attributes. |
| For example, it is common to assume that `a/b` means `a` will immediate precede `b`, |
| which is not the case. |
| It is also common to assume that `a/b=false` is equivalent to `b/a=true`, |
| which is not the case (it has no effect). |
| |
| . Typing relative ordering attributes in an XML layer is slow and results in bloat |
| since most filenames have to be written three times: |
| |
| [source,xml] |
| ---- |
| <file name="a"/> |
| <attr name="a/b" boolvalue="true"/> |
| <file name="b"/> |
| <attr name="b/c" boolvalue="true"/> |
| <file name="c"/> |
| <attr name="c/d" boolvalue="true"/> |
| <file name="d"/> |
| ---- |
| |
| . When many unrelated modules contribute to a folder, it is often not clear which modules |
| are more fundamental. (The convention is to have more optional modules declare order |
| relative to more fundamental modules, so the fundamental modules need not know about |
| the optional modules.) |
| |
| To ensure that the folder order will hold up even when some modules are disabled, |
| it is common to overspecify ordering, which can lead to a near-quadratic number of attrs; |
| when this is not done, it is common for folders to fall into haphazard order |
| as the set of modules changes in unexpected ways. |
| |
| |
| . Attributes often need to be edited to accommodate renames or other changes |
| of unrelated files. |
| |
| . Contradictory orderings lead to `TopologicalSortException`s, which are unfriendly |
| and difficult to debug. |
| |
| . The module development support has a difficult time writing out ordering attributes |
| when the developer uses drag-and-drop to reorder files in an XML layer. |
| |
| |
| [[Solution]] |
| === Solution |
| |
| To address these problems, the solution is to add a fifth means of ordering a folder. |
| Every file in the folder could have a `Number`-valued attribute `position`. |
| Files would then be sorted (in increasing order) by position. |
| This would also be consistent with `Lookups.metaInfServices`. |
| |
| For example: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| <file name="a"><attr name="position" intvalue="100"/></file> |
| <file name="b"><attr name="position" intvalue="200"/></file> |
| <file name="c"><attr name="position" intvalue="300"/></file> |
| <file name="d"><attr name="position" intvalue="400"/></file> |
| ---- |
| |
| |
| [[Details]] |
| == Details |
| |
| |
| [[Ordering_semantics]] |
| === Ordering semantics |
| |
| Normally positive integers would be used for positions, |
| but floats or negative integers could be used for emergencies |
| in case an item needed to be inserted between two adjacent integers. |
| |
| Files with no marked position would be placed at the end (and a brief warning logged). |
| Files with the same position would be ordered alphabetically (and a brief warning logged). |
| As an exception, you may mark files with the position 0 to indicate that |
| their position is irrelevant; |
| no warning is logged if several such files exist in the same folder. |
| |
| Numeric and relative ordering can coexist, for backwards compatibility. |
| |
| Uses of relative ordering attributes should be logged as warnings |
| to assist in migration. |
| |
| |
| [[Setting_order]] |
| === Setting order |
| |
| `DataFolder.setOrder` should remove any of the old ordering methods in effect |
| and set positions on each file in the folder. |
| The tricky part is to avoid changing the positions of files which already have positions |
| unless necessary to accommodate the new order. |
| |
| For example, given an initial folder content: |
| |
| [source] |
| ---- |
| a (#100) |
| b (#200) |
| c (#300) |
| d |
| ---- |
| |
| and asked to set the order to `d a c b`, |
| it would be best to change only two attributes, e.g.: |
| |
| [source] |
| ---- |
| d (#0) |
| a (#100) |
| c (#300) |
| b (#400) |
| ---- |
| |
| or something similar. |
| |
| I.e. first need to compute a minimal set of transpositions. |
| |
| TIP: decompose permutation graph into disjoint cycles. |
| |
| Then use some heuristics to decide |
| which of a pair in a transposition to "move", |
| and what its new position should be. |
| Heuristics could include: |
| |
| 1. Prefer to add a position to a file which lacks one than to change an existing position. |
| . Prefer round numbers like 100 to numbers like 123, and prefer integers to floats. |
| . Prefer to move a locally modified file to an untouched one. |
| (Can be implemented by looking at position of a `MultiFileObject`'s leader filesystem.) |
| |
| |
| [[Java_APIs]] |
| === Java APIs |
| |
| Introduce methods to order a folder in `FileUtil` in the Filesystems API, |
| and to set a new order. |
| This avoids duplicating somewhat subtle code. |
| Since callers might be ignoring some files in a folder (e.g. `*.form`) |
| the list of files to consider needs to be passed as well. |
| |
| [source,java,subs="{markup-in-source}"] |
| ---- |
| class FileUtil { |
| public static List<FileObject> getOrder(Collection<FileObject> children, boolean logWarnings); |
| /** @postcondition children = getOrder(children, false) */ |
| public static void setOrder(List<FileObject> children) throws IOException; |
| public static boolean affectsOrder(FileAttributeEvent event); |
| // ... |
| } |
| ---- |
| |
| (used in: `core/startup`, `core/windows`, `editor/mimelookup/impl`, `openide/loaders`) |
| |
| |
| [[Separators]] |
| === Separators |
| |
| For menu folders and other places where there is a distinguished null value |
| or other separator, |
| it is generally permitted to have extra separators. |
| (Leading, trailing, or adjacent duplicate separators are ignored.) |
| With numeric ordering, a simple convention could help group items into separated blocks. |
| |
| For example: |
| |
| [source,xml,subs="{markup-in-source}"] |
| ---- |
| |
| <file name="sep500"><attr name="position" intvalue="500"/></file> |
| <file name="cut"><attr name="position" intvalue="600"/></file> |
| <file name="copy"><attr name="position" intvalue="700"/></file> |
| <file name="paste"><attr name="position" intvalue="800"/></file> |
| <file name="delete"><attr name="position" intvalue="900"/></file> |
| <file name="sep1000"><attr name="position" intvalue="1000"/></file> |
| <file name="undo"><attr name="position" intvalue="1200"/></file> |
| <file name="redo"><attr name="position" intvalue="1300"/></file> |
| <file name="sep1500"><attr name="position" intvalue="1500"/></file> |
| ---- |
| |
| will display as: |
| |
| [source,java,subs="{markup-in-source}"] |
| ---- |
| |
| cut |
| copy |
| paste |
| delete |
| ------ |
| undo |
| redo |
| ---- |
| |
| but it is easy to add new items at the top, bottom, or middle of any block; |
| add new blocks at any position; divide existing blocks; etc. |
| |
| |
| [[SideBar_and_position_attributes]] |
| === SideBar and position attributes |
| |
| The editor folders under `SideBar` were using a `position` |
| attribute for a different purpose. |
| These have been converted (compatibly) to use `location` instead. |
| |
| |
| [[Changed_code]] |
| == Changed code |
| |
| Scope is "Big IDE" with all clusters (incl. CND and Profiler). |
| |
| |
| [[Readers_of_relative_ordering_attrs]] |
| === Readers of relative ordering attrs |
| |
| * `FolderOrder` (`openide/loaders`; also `DataFolder` and `FolderList`) |
| This is the canonical reader of ordering attributes. |
| |
| * `CompoundFolderChildren` (`editor/mimelookup/impl`; also `FolderChildren`) |
| Does its own reading to order the result of merging together several folders. |
| Víťa agrees it could probably be changed to use `MultiFileSystem` instead, |
| or could use any new sorting API (if it supported parallel folders), |
| or could directly implement sorting by position. |
| |
| * `OptionUtilities` (`editor`) |
| Víťa says it is semi-obsolete, but similar to `CompoundFolderChildren`. |
| |
| * `ModeParser` (`core/windows`) |
| Prefers to operate at Filesystems API level, for efficiency and predictability. |
| (Using `DataFolder` is slower and introduces asynchronous behavior.) |
| |
| * `RecognizeInstanceFiles` (`core/startup`) |
| Cannot refer to Datasystems API. |
| |
| |
| [[Writers_of_relative_ordering_attrs]] |
| === Writers of relative ordering attrs |
| |
| * `LanguagesManager` (`languages/engine`) _(needs tuning)_ |
| * `MenuFolderNode` and `ToolbarFolderNode` (`core/windows`) |
| * `CreatedModifiedFiles` (`apisupport/project`; also `ui.wizard.action.DataModel`) |
| * `WritableXMLFileSystem` (`apisupport/project`) |
| * `LanguageRegistry` (`scripting/gsf`) _(needs tuning)_ |
| * `MidpPaletteProvider` (`mobility/designer2/midp`) _(done though untested)_ |
| |
| |
| [[Uses_of_relative_ordering_attrs]] |
| === Uses of relative ordering attrs |
| |
| Fixed in bulk mode using `apisupport/relative2position`. |
| |
| [[Commit_validation]] |
| === Commit validation |
| |
| `ValidateLayerConsistencyTest` (in `core`) should verify that: |
| |
| 1. No relative ordering attributes are in use on any folder. |
| . Neither `OpenIDE-Folder-Order` nor `OpenIDE-Folder-SortMode` are used. |
| . Any `position` attribute has a numeric value. |
| . If any file (or subfolder) in a folder has a `position` attribute, |
| then they all do; and all the values are distinct. |
| |
| _Implemented._ |
| Run not only in the `trunk` Hudson project (i.e. full IDE), |
| but also in `nbms-and-javadoc` (to check experimental modules). |
| |
| |
| [[API_Docs_Updated]] |
| === API Docs Updated |
| |
| * Modules API. |
| * `editor/mimelookup/impl` Javadoc |
| * xref:./DevFaqOrderAttributes.adoc[DevFaqOrderAttributes] |
| * xref:./NewAndNoteWorthyMilestone10.adoc[NewAndNoteWorthyMilestone10] |
| |
| |
| [[Misc._impl_still_left_to_do]] |
| === Misc. impl still left to do |
| |
| * Fix up `LanguagesManager` and `LanguageRegistry`. |
| _(some fixes done already; remainder probably best left to domain developers)_ |
| |
| * Change `FileUtil.setOrder` to be more conservative: |
| avoid changing existing `position` attributes if possible. |
| ''(in progress; cf. |
| link:https://bz.apache.org/netbeans/show_bug.cgi?id=110981[issue #110981])'' |
| |
| * Fix up various ordering attrs which are not quite right. |
| Especially files which claim to be ordered in folders which do not care. |
| Also `Editors/text/*+xml/**` (e.g. Ant context menu) are generally not right. |
| _(generally will be left to whoever handles UI spec conformance bugs)_ |
| |
| * `nbbuild/build.xml#index-layer-paths` ought to order files. _(done)_ |
| * Need some way of marking a file as not intended to be ordered. |
| E.g. position="0" or position="none". |
| Useful for e.g. hidden subfolders. |
| `getOrder` can put these wherever it likes but should never warn about them. |
| link:https://bz.apache.org/netbeans/show_bug.cgi?id=107550[Issue #107550] _(done)_ |
| |
| * Clean up experimental modules. |
| link:http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/lastSuccessfulBuild/testReport/org.netbeans.core.projects/ValidateLayerConsistencyTest/testFolderOrdering/[Current errors] |
| _(done)_ |