123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935 |
- /*
- ==============================================================================
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
- JUCE is an open source library subject to commercial or open-source
- licensing.
- By using JUCE, you agree to the terms of both the JUCE 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-privacy-policy
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
- ==============================================================================
- */
- namespace juce
- {
- class TreeView;
- //==============================================================================
- /**
- An item in a treeview.
- A TreeViewItem can either be a leaf-node in the tree, or it can contain its
- own sub-items.
- To implement an item that contains sub-items, override the itemOpennessChanged()
- method so that when it is opened, it adds the new sub-items to itself using the
- addSubItem method. Depending on the nature of the item it might choose to only
- do this the first time it's opened, or it might want to refresh itself each time.
- It also has the option of deleting its sub-items when it is closed, or leaving them
- in place.
- @tags{GUI}
- */
- class JUCE_API TreeViewItem
- {
- public:
- //==============================================================================
- /** Constructor. */
- TreeViewItem();
- /** Destructor. */
- virtual ~TreeViewItem();
- //==============================================================================
- /** Returns the number of sub-items that have been added to this item.
- Note that this doesn't mean much if the node isn't open.
- @see getSubItem, mightContainSubItems, addSubItem
- */
- int getNumSubItems() const noexcept;
- /** Returns one of the item's sub-items.
- Remember that the object returned might get deleted at any time when its parent
- item is closed or refreshed, depending on the nature of the items you're using.
- @see getNumSubItems
- */
- TreeViewItem* getSubItem (int index) const noexcept;
- /** Removes any sub-items. */
- void clearSubItems();
- /** Adds a sub-item.
- @param newItem the object to add to the item's sub-item list. Once added, these can be
- found using getSubItem(). When the items are later removed with
- removeSubItem() (or when this item is deleted), they will be deleted.
- @param insertPosition the index which the new item should have when it's added. If this
- value is less than 0, the item will be added to the end of the list.
- */
- void addSubItem (TreeViewItem* newItem, int insertPosition = -1);
- /** Adds a sub-item with a sort-comparator, assuming that the existing items are already sorted.
- @param comparator the comparator object for sorting - see sortSubItems() for details about
- the methods this class must provide.
- @param newItem the object to add to the item's sub-item list. Once added, these can be
- found using getSubItem(). When the items are later removed with
- removeSubItem() (or when this item is deleted), they will be deleted.
- */
- template <class ElementComparator>
- void addSubItemSorted (ElementComparator& comparator, TreeViewItem* newItem)
- {
- addSubItem (newItem, findInsertIndexInSortedArray (comparator, subItems.begin(), newItem, 0, subItems.size()));
- }
- /** Removes one of the sub-items.
- @param index the item to remove
- @param deleteItem if true, the item that is removed will also be deleted.
- */
- void removeSubItem (int index, bool deleteItem = true);
- /** Sorts the list of sub-items using a standard array comparator.
- This will use a comparator object to sort the elements into order. The comparator
- object must have a method of the form:
- @code
- int compareElements (TreeViewItem* first, TreeViewItem* second);
- @endcode
- ..and this method must return:
- - a value of < 0 if the first comes before the second
- - a value of 0 if the two objects are equivalent
- - a value of > 0 if the second comes before the first
- To improve performance, the compareElements() method can be declared as static or const.
- */
- template <class ElementComparator>
- void sortSubItems (ElementComparator& comparator)
- {
- subItems.sort (comparator);
- }
- //==============================================================================
- /** Returns the TreeView to which this item belongs. */
- TreeView* getOwnerView() const noexcept { return ownerView; }
- /** Returns the item within which this item is contained. */
- TreeViewItem* getParentItem() const noexcept { return parentItem; }
- //==============================================================================
- /** True if this item is currently open in the treeview.
- @see getOpenness
- */
- bool isOpen() const noexcept;
- /** Opens or closes the item.
- When opened or closed, the item's itemOpennessChanged() method will be called,
- and a subclass should use this callback to create and add any sub-items that
- it needs to.
- Note that if this is called when the item is in its default openness state, and
- this call would not change whether it's open or closed, then no change will be
- stored. If you want to explicitly set the openness state to be non-default then
- you should use setOpenness instead.
- @see setOpenness, itemOpennessChanged, mightContainSubItems
- */
- void setOpen (bool shouldBeOpen);
- /** An enum of states to describe the explicit or implicit openness of an item. */
- enum Openness
- {
- opennessDefault = 0,
- opennessClosed = 1,
- opennessOpen = 2
- };
- /** Returns the openness state of this item.
- @see isOpen
- */
- Openness getOpenness() const noexcept;
- /** Opens or closes the item.
- If this causes the value of isOpen() to change, then the item's itemOpennessChanged()
- method will be called, and a subclass should use this callback to create and add any
- sub-items that it needs to.
- @see setOpen
- */
- void setOpenness (Openness newOpenness);
- /** True if this item is currently selected.
- Use this when painting the node, to decide whether to draw it as selected or not.
- */
- bool isSelected() const noexcept;
- /** Selects or deselects the item.
- If shouldNotify == sendNotification, then a callback will be made
- to itemSelectionChanged() if the item's selection has changed.
- */
- void setSelected (bool shouldBeSelected,
- bool deselectOtherItemsFirst,
- NotificationType shouldNotify = sendNotification);
- /** Returns the rectangle that this item occupies.
- If relativeToTreeViewTopLeft is true, the coordinates are relative to the
- top-left of the TreeView comp, so this will depend on the scroll-position of
- the tree. If false, it is relative to the top-left of the topmost item in the
- tree (so this would be unaffected by scrolling the view).
- */
- Rectangle<int> getItemPosition (bool relativeToTreeViewTopLeft) const noexcept;
- /** Sends a signal to the treeview to make it refresh itself.
- Call this if your items have changed and you want the tree to update to reflect this.
- */
- void treeHasChanged() const noexcept;
- /** Sends a repaint message to redraw just this item.
- Note that you should only call this if you want to repaint a superficial change. If
- you're altering the tree's nodes, you should instead call treeHasChanged().
- */
- void repaintItem() const;
- /** Returns the row number of this item in the tree.
- The row number of an item will change according to which items are open.
- @see TreeView::getNumRowsInTree(), TreeView::getItemOnRow()
- */
- int getRowNumberInTree() const noexcept;
- /** Returns true if all the item's parent nodes are open.
- This is useful to check whether the item might actually be visible or not.
- */
- bool areAllParentsOpen() const noexcept;
- /** Changes whether lines are drawn to connect any sub-items to this item.
- By default, line-drawing is turned on according to LookAndFeel::areLinesDrawnForTreeView().
- */
- void setLinesDrawnForSubItems (bool shouldDrawLines) noexcept;
- //==============================================================================
- /** Tells the tree whether this item can potentially be opened.
- If your item could contain sub-items, this should return true; if it returns
- false then the tree will not try to open the item. This determines whether or
- not the item will be drawn with a 'plus' button next to it.
- */
- virtual bool mightContainSubItems() = 0;
- /** Returns a string to uniquely identify this item.
- If you're planning on using the TreeView::getOpennessState() method, then
- these strings will be used to identify which nodes are open. The string
- should be unique amongst the item's sibling items, but it's ok for there
- to be duplicates at other levels of the tree.
- If you're not going to store the state, then it's ok not to bother implementing
- this method.
- */
- virtual String getUniqueName() const;
- /** Called when an item is opened or closed.
- When setOpen() is called and the item has specified that it might
- have sub-items with the mightContainSubItems() method, this method
- is called to let the item create or manage its sub-items.
- So when this is called with isNowOpen set to true (i.e. when the item is being
- opened), a subclass might choose to use clearSubItems() and addSubItem() to
- refresh its sub-item list.
- When this is called with isNowOpen set to false, the subclass might want
- to use clearSubItems() to save on space, or it might choose to leave them,
- depending on the nature of the tree.
- You could also use this callback as a trigger to start a background process
- which asynchronously creates sub-items and adds them, if that's more
- appropriate for the task in hand.
- @see mightContainSubItems
- */
- virtual void itemOpennessChanged (bool isNowOpen);
- /** Must return the width required by this item.
- If your item needs to have a particular width in pixels, return that value; if
- you'd rather have it just fill whatever space is available in the treeview,
- return -1.
- If all your items return -1, no horizontal scrollbar will be shown, but if any
- items have fixed widths and extend beyond the width of the treeview, a
- scrollbar will appear.
- Each item can be a different width, but if they change width, you should call
- treeHasChanged() to update the tree.
- */
- virtual int getItemWidth() const { return -1; }
- /** Must return the height required by this item.
- This is the height in pixels that the item will take up. Items in the tree
- can be different heights, but if they change height, you should call
- treeHasChanged() to update the tree.
- */
- virtual int getItemHeight() const { return 20; }
- /** You can override this method to return false if you don't want to allow the
- user to select this item.
- */
- virtual bool canBeSelected() const { return true; }
- /** Creates a component that will be used to represent this item.
- You don't have to implement this method - if it returns nullptr then no component
- will be used for the item, and you can just draw it using the paintItem()
- callback. But if you do return a component, it will be positioned in the
- treeview so that it can be used to represent this item.
- The component returned will be managed by the treeview, so always return
- a new component, and don't keep a reference to it, as the treeview will
- delete it later when it goes off the screen or is no longer needed. Also
- bear in mind that if the component keeps a reference to the item that
- created it, that item could be deleted before the component. Its position
- and size will be completely managed by the tree, so don't attempt to move it
- around.
- Something you may want to do with your component is to give it a pointer to
- the TreeView that created it. This is perfectly safe, and there's no danger
- of it becoming a dangling pointer because the TreeView will always delete
- the component before it is itself deleted.
- As long as you stick to these rules you can return whatever kind of
- component you like. It's most useful if you're doing things like drag-and-drop
- of items, or want to use a Label component to edit item names, etc.
- */
- virtual Component* createItemComponent() { return nullptr; }
- //==============================================================================
- /** Draws the item's contents.
- You can choose to either implement this method and draw each item, or you
- can use createItemComponent() to create a component that will represent the
- item.
- If all you need in your tree is to be able to draw the items and detect when
- the user selects or double-clicks one of them, it's probably enough to
- use paintItem(), itemClicked() and itemDoubleClicked(). If you need more
- complicated interactions, you may need to use createItemComponent() instead.
- @param g the graphics context to draw into
- @param width the width of the area available for drawing
- @param height the height of the area available for drawing
- */
- virtual void paintItem (Graphics& g, int width, int height);
- /** Draws the item's open/close button.
- If you don't implement this method, the default behaviour is to call
- LookAndFeel::drawTreeviewPlusMinusBox(), but you can override it for custom
- effects. You may want to override it and call the base-class implementation
- with a different backgroundColour parameter, if your implementation has a
- background colour other than the default (white).
- */
- virtual void paintOpenCloseButton (Graphics&, const Rectangle<float>& area,
- Colour backgroundColour, bool isMouseOver);
- /** Draws the line that connects this item to the vertical line extending below its parent. */
- virtual void paintHorizontalConnectingLine (Graphics&, const Line<float>& line);
- /** Draws the line that extends vertically up towards one of its parents, or down to one of its children. */
- virtual void paintVerticalConnectingLine (Graphics&, const Line<float>& line);
- /** Called when the user clicks on this item.
- If you're using createItemComponent() to create a custom component for the
- item, the mouse-clicks might not make it through to the treeview, but this
- is how you find out about clicks when just drawing each item individually.
- The associated mouse-event details are passed in, so you can find out about
- which button, where it was, etc.
- @see itemDoubleClicked
- */
- virtual void itemClicked (const MouseEvent&);
- /** Called when the user double-clicks on this item.
- If you're using createItemComponent() to create a custom component for the
- item, the mouse-clicks might not make it through to the treeview, but this
- is how you find out about clicks when just drawing each item individually.
- The associated mouse-event details are passed in, so you can find out about
- which button, where it was, etc.
- If not overridden, the base class method here will open or close the item as
- if the 'plus' button had been clicked.
- @see itemClicked
- */
- virtual void itemDoubleClicked (const MouseEvent&);
- /** Called when the item is selected or deselected.
- Use this if you want to do something special when the item's selectedness
- changes. By default it'll get repainted when this happens.
- */
- virtual void itemSelectionChanged (bool isNowSelected);
- /** Called when the owner view changes */
- virtual void ownerViewChanged (TreeView* newOwner);
- /** The item can return a tool tip string here if it wants to.
- @see TooltipClient
- */
- virtual String getTooltip();
- //==============================================================================
- /** To allow items from your treeview to be dragged-and-dropped, implement this method.
- If this returns a non-null variant then when the user drags an item, the treeview will
- try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger
- a drag-and-drop operation, using this string as the source description, with the treeview
- itself as the source component.
- If you need more complex drag-and-drop behaviour, you can use custom components for
- the items, and use those to trigger the drag.
- To accept drag-and-drop in your tree, see isInterestedInDragSource(),
- isInterestedInFileDrag(), etc.
- @see DragAndDropContainer::startDragging
- */
- virtual var getDragSourceDescription();
- /** If you want your item to be able to have files drag-and-dropped onto it, implement this
- method and return true.
- If you return true and allow some files to be dropped, you'll also need to implement the
- filesDropped() method to do something with them.
- Note that this will be called often, so make your implementation very quick! There's
- certainly no time to try opening the files and having a think about what's inside them!
- For responding to internal drag-and-drop of other types of object, see isInterestedInDragSource().
- @see FileDragAndDropTarget::isInterestedInFileDrag, isInterestedInDragSource
- */
- virtual bool isInterestedInFileDrag (const StringArray& files);
- /** When files are dropped into this item, this callback is invoked.
- For this to work, you'll need to have also implemented isInterestedInFileDrag().
- The insertIndex value indicates where in the list of sub-items the files were dropped.
- If files are dropped onto an area of the tree where there are no visible items, this
- method is called on the root item of the tree, with an insert index of 0.
- @see FileDragAndDropTarget::filesDropped, isInterestedInFileDrag
- */
- virtual void filesDropped (const StringArray& files, int insertIndex);
- /** If you want your item to act as a DragAndDropTarget, implement this method and return true.
- If you implement this method, you'll also need to implement itemDropped() in order to handle
- the items when they are dropped.
- To respond to drag-and-drop of files from external applications, see isInterestedInFileDrag().
- @see DragAndDropTarget::isInterestedInDragSource, itemDropped
- */
- virtual bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails);
- /** When a things are dropped into this item, this callback is invoked.
- For this to work, you need to have also implemented isInterestedInDragSource().
- The insertIndex value indicates where in the list of sub-items the new items should be placed.
- If files are dropped onto an area of the tree where there are no visible items, this
- method is called on the root item of the tree, with an insert index of 0.
- @see isInterestedInDragSource, DragAndDropTarget::itemDropped
- */
- virtual void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex);
- //==============================================================================
- /** Sets a flag to indicate that the item wants to be allowed
- to draw all the way across to the left edge of the treeview.
- By default this is false, which means that when the paintItem()
- method is called, its graphics context is clipped to only allow
- drawing within the item's rectangle. If this flag is set to true,
- then the graphics context isn't clipped on its left side, so it
- can draw all the way across to the left margin. Note that the
- context will still have its origin in the same place though, so
- the coordinates of anything to its left will be negative. It's
- mostly useful if you want to draw a wider bar behind the
- highlighted item.
- */
- void setDrawsInLeftMargin (bool canDrawInLeftMargin) noexcept;
- /** Sets a flag to indicate that the item wants to be allowed
- to draw all the way across to the right edge of the treeview.
- Similar to setDrawsInLeftMargin: when this flag is set to true,
- then the graphics context isn't clipped on the right side. Unlike
- setDrawsInLeftMargin, you will very rarely need to use this function,
- as this method won't clip the right margin unless your TreeViewItem
- overrides getItemWidth to return a positive value.
- @see setDrawsInLeftMargin, getItemWidth
- */
- void setDrawsInRightMargin (bool canDrawInRightMargin) noexcept;
- //==============================================================================
- /** Saves the current state of open/closed nodes so it can be restored later.
- This takes a snapshot of which sub-nodes have been explicitly opened or closed,
- and records it as XML. To identify node objects it uses the
- TreeViewItem::getUniqueName() method to create named paths. This
- means that the same state of open/closed nodes can be restored to a
- completely different instance of the tree, as long as it contains nodes
- whose unique names are the same.
- You'd normally want to use TreeView::getOpennessState() rather than call it
- for a specific item, but this can be handy if you need to briefly save the state
- for a section of the tree.
- The caller is responsible for deleting the object that is returned.
- Note that if all nodes of the tree are in their default state, then this may
- return a nullptr.
- @see TreeView::getOpennessState, restoreOpennessState
- */
- std::unique_ptr<XmlElement> getOpennessState() const;
- /** Restores the openness of this item and all its sub-items from a saved state.
- See TreeView::restoreOpennessState for more details.
- You'd normally want to use TreeView::restoreOpennessState() rather than call it
- for a specific item, but this can be handy if you need to briefly save the state
- for a section of the tree.
- @see TreeView::restoreOpennessState, getOpennessState
- */
- void restoreOpennessState (const XmlElement& xml);
- //==============================================================================
- /** Returns the index of this item in its parent's sub-items. */
- int getIndexInParent() const noexcept;
- /** Returns true if this item is the last of its parent's sub-items. */
- bool isLastOfSiblings() const noexcept;
- /** Creates a string that can be used to uniquely retrieve this item in the tree.
- The string that is returned can be passed to TreeView::findItemFromIdentifierString().
- The string takes the form of a path, constructed from the getUniqueName() of this
- item and all its parents, so these must all be correctly implemented for it to work.
- @see TreeView::findItemFromIdentifierString, getUniqueName
- */
- String getItemIdentifierString() const;
- //==============================================================================
- /**
- This handy class takes a copy of a TreeViewItem's openness when you create it,
- and restores that openness state when its destructor is called.
- This can very handy when you're refreshing sub-items - e.g.
- @code
- void MyTreeViewItem::updateChildItems()
- {
- OpennessRestorer openness (*this); // saves the openness state here..
- clearSubItems();
- // add a bunch of sub-items here which may or may not be the same as the ones that
- // were previously there
- addSubItem (...
- // ..and at this point, the old openness is restored, so any items that haven't
- // changed will have their old openness retained.
- }
- @endcode
- */
- class OpennessRestorer
- {
- public:
- OpennessRestorer (TreeViewItem&);
- ~OpennessRestorer();
- private:
- TreeViewItem& treeViewItem;
- std::unique_ptr<XmlElement> oldOpenness;
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpennessRestorer)
- };
- private:
- //==============================================================================
- TreeView* ownerView = nullptr;
- TreeViewItem* parentItem = nullptr;
- OwnedArray<TreeViewItem> subItems;
- int y = 0, itemHeight = 0, totalHeight = 0, itemWidth = 0, totalWidth = 0;
- int uid = 0;
- bool selected : 1;
- bool redrawNeeded : 1;
- bool drawLinesInside : 1;
- bool drawLinesSet : 1;
- bool drawsInLeftMargin : 1;
- bool drawsInRightMargin : 1;
- unsigned int openness : 2;
- friend class TreeView;
- void updatePositions (int newY);
- int getIndentX() const noexcept;
- void setOwnerView (TreeView*) noexcept;
- void paintRecursively (Graphics&, int width);
- TreeViewItem* getTopLevelItem() noexcept;
- TreeViewItem* findItemRecursively (int y) noexcept;
- TreeViewItem* getDeepestOpenParentItem() noexcept;
- int getNumRows() const noexcept;
- TreeViewItem* getItemOnRow (int index) noexcept;
- void deselectAllRecursively (TreeViewItem* itemToIgnore);
- int countSelectedItemsRecursively (int depth) const noexcept;
- TreeViewItem* getSelectedItemWithIndex (int index) noexcept;
- TreeViewItem* getNextVisibleItem (bool recurse) const noexcept;
- TreeViewItem* findItemFromIdentifierString (const String&);
- void restoreToDefaultOpenness();
- bool isFullyOpen() const noexcept;
- XmlElement* getOpennessState (bool canReturnNull) const;
- bool removeSubItemFromList (int index, bool deleteItem);
- void removeAllSubItemsFromList();
- bool areLinesDrawn() const;
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeViewItem)
- };
- //==============================================================================
- /**
- A tree-view component.
- Use one of these to hold and display a structure of TreeViewItem objects.
- @tags{GUI}
- */
- class JUCE_API TreeView : public Component,
- public SettableTooltipClient,
- public FileDragAndDropTarget,
- public DragAndDropTarget
- {
- public:
- //==============================================================================
- /** Creates an empty treeview.
- Once you've got a treeview component, you'll need to give it something to
- display, using the setRootItem() method.
- */
- TreeView (const String& componentName = String());
- /** Destructor. */
- ~TreeView() override;
- //==============================================================================
- /** Sets the item that is displayed in the treeview.
- A tree has a single root item which contains as many sub-items as it needs. If
- you want the tree to contain a number of root items, you should still use a single
- root item above these, but hide it using setRootItemVisible().
- You can pass nullptr to this method to clear the tree and remove its current root item.
- The object passed in will not be deleted by the treeview, it's up to the caller
- to delete it when no longer needed. BUT make absolutely sure that you don't delete
- this item until you've removed it from the tree, either by calling setRootItem (nullptr),
- or by deleting the tree first. You can also use deleteRootItem() as a quick way
- to delete it.
- */
- void setRootItem (TreeViewItem* newRootItem);
- /** Returns the tree's root item.
- This will be the last object passed to setRootItem(), or nullptr if none has been set.
- */
- TreeViewItem* getRootItem() const noexcept { return rootItem; }
- /** This will remove and delete the current root item.
- It's a convenient way of deleting the item and calling setRootItem (nullptr).
- */
- void deleteRootItem();
- /** Changes whether the tree's root item is shown or not.
- If the root item is hidden, only its sub-items will be shown in the treeview - this
- lets you make the tree look as if it's got many root items. If it's hidden, this call
- will also make sure the root item is open (otherwise the treeview would look empty).
- */
- void setRootItemVisible (bool shouldBeVisible);
- /** Returns true if the root item is visible.
- @see setRootItemVisible
- */
- bool isRootItemVisible() const noexcept { return rootItemVisible; }
- /** Sets whether items are open or closed by default.
- Normally, items are closed until the user opens them, but you can use this
- to make them default to being open until explicitly closed.
- @see areItemsOpenByDefault
- */
- void setDefaultOpenness (bool isOpenByDefault);
- /** Returns true if the tree's items default to being open.
- @see setDefaultOpenness
- */
- bool areItemsOpenByDefault() const noexcept { return defaultOpenness; }
- /** This sets a flag to indicate that the tree can be used for multi-selection.
- You can always select multiple items internally by calling the
- TreeViewItem::setSelected() method, but this flag indicates whether the user
- is allowed to multi-select by clicking on the tree.
- By default it is disabled.
- @see isMultiSelectEnabled
- */
- void setMultiSelectEnabled (bool canMultiSelect);
- /** Returns whether multi-select has been enabled for the tree.
- @see setMultiSelectEnabled
- */
- bool isMultiSelectEnabled() const noexcept { return multiSelectEnabled; }
- /** Sets a flag to indicate whether to hide the open/close buttons.
- @see areOpenCloseButtonsVisible
- */
- void setOpenCloseButtonsVisible (bool shouldBeVisible);
- /** Returns whether open/close buttons are shown.
- @see setOpenCloseButtonsVisible
- */
- bool areOpenCloseButtonsVisible() const noexcept { return openCloseButtonsVisible; }
- //==============================================================================
- /** Deselects any items that are currently selected. */
- void clearSelectedItems();
- /** Returns the number of items that are currently selected.
- If maximumDepthToSearchTo is >= 0, it lets you specify a maximum depth to which the
- tree will be recursed.
- @see getSelectedItem, clearSelectedItems
- */
- int getNumSelectedItems (int maximumDepthToSearchTo = -1) const noexcept;
- /** Returns one of the selected items in the tree.
- @param index the index, 0 to (getNumSelectedItems() - 1)
- */
- TreeViewItem* getSelectedItem (int index) const noexcept;
- /** Moves the selected row up or down by the specified number of rows. */
- void moveSelectedRow (int deltaRows);
- //==============================================================================
- /** Returns the number of rows the tree is using.
- This will depend on which items are open.
- @see TreeViewItem::getRowNumberInTree()
- */
- int getNumRowsInTree() const;
- /** Returns the item on a particular row of the tree.
- If the index is out of range, this will return nullptr.
- @see getNumRowsInTree, TreeViewItem::getRowNumberInTree()
- */
- TreeViewItem* getItemOnRow (int index) const;
- /** Returns the item that contains a given y position.
- The y is relative to the top of the TreeView component.
- */
- TreeViewItem* getItemAt (int yPosition) const noexcept;
- /** Tries to scroll the tree so that this item is on-screen somewhere. */
- void scrollToKeepItemVisible (TreeViewItem* item);
- /** Returns the treeview's Viewport object. */
- Viewport* getViewport() const noexcept;
- /** Returns the number of pixels by which each nested level of the tree is indented.
- @see setIndentSize
- */
- int getIndentSize() noexcept;
- /** Changes the distance by which each nested level of the tree is indented.
- @see getIndentSize
- */
- void setIndentSize (int newIndentSize);
- /** Searches the tree for an item with the specified identifier.
- The identifier string must have been created by calling TreeViewItem::getItemIdentifierString().
- If no such item exists, this will return false. If the item is found, all of its items
- will be automatically opened.
- */
- TreeViewItem* findItemFromIdentifierString (const String& identifierString) const;
- //==============================================================================
- /** Saves the current state of open/closed nodes so it can be restored later.
- This takes a snapshot of which nodes have been explicitly opened or closed,
- and records it as XML. To identify node objects it uses the
- TreeViewItem::getUniqueName() method to create named paths. This
- means that the same state of open/closed nodes can be restored to a
- completely different instance of the tree, as long as it contains nodes
- whose unique names are the same.
- The caller is responsible for deleting the object that is returned.
- @param alsoIncludeScrollPosition if this is true, the state will also
- include information about where the
- tree has been scrolled to vertically,
- so this can also be restored
- @see restoreOpennessState
- */
- std::unique_ptr<XmlElement> getOpennessState (bool alsoIncludeScrollPosition) const;
- /** Restores a previously saved arrangement of open/closed nodes.
- This will try to restore a snapshot of the tree's state that was created by
- the getOpennessState() method. If any of the nodes named in the original
- XML aren't present in this tree, they will be ignored.
- If restoreStoredSelection is true, it will also try to re-select any items that
- were selected in the stored state.
- @see getOpennessState
- */
- void restoreOpennessState (const XmlElement& newState,
- bool restoreStoredSelection);
- //==============================================================================
- /** A set of colour IDs to use to change the colour of various aspects of the treeview.
- These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
- methods.
- @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
- */
- enum ColourIds
- {
- backgroundColourId = 0x1000500, /**< A background colour to fill the component with. */
- linesColourId = 0x1000501, /**< The colour to draw the lines with.*/
- dragAndDropIndicatorColourId = 0x1000502, /**< The colour to use for the drag-and-drop target position indicator. */
- selectedItemBackgroundColourId = 0x1000503, /**< The colour to use to fill the background of any selected items. */
- oddItemsColourId = 0x1000504, /**< The colour to use to fill the background of the odd numbered items. */
- evenItemsColourId = 0x1000505 /**< The colour to use to fill the background of the even numbered items. */
- };
- //==============================================================================
- /** This abstract base class is implemented by LookAndFeel classes to provide
- treeview drawing functionality.
- */
- struct JUCE_API LookAndFeelMethods
- {
- virtual ~LookAndFeelMethods() = default;
- virtual void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area,
- Colour backgroundColour, bool isItemOpen, bool isMouseOver) = 0;
- virtual bool areLinesDrawnForTreeView (TreeView&) = 0;
- virtual int getTreeViewIndentSize (TreeView&) = 0;
- };
- //==============================================================================
- /** @internal */
- void paint (Graphics&) override;
- /** @internal */
- void resized() override;
- /** @internal */
- bool keyPressed (const KeyPress&) override;
- /** @internal */
- void colourChanged() override;
- /** @internal */
- void enablementChanged() override;
- /** @internal */
- bool isInterestedInFileDrag (const StringArray& files) override;
- /** @internal */
- void fileDragEnter (const StringArray& files, int x, int y) override;
- /** @internal */
- void fileDragMove (const StringArray& files, int x, int y) override;
- /** @internal */
- void fileDragExit (const StringArray& files) override;
- /** @internal */
- void filesDropped (const StringArray& files, int x, int y) override;
- /** @internal */
- bool isInterestedInDragSource (const SourceDetails&) override;
- /** @internal */
- void itemDragEnter (const SourceDetails&) override;
- /** @internal */
- void itemDragMove (const SourceDetails&) override;
- /** @internal */
- void itemDragExit (const SourceDetails&) override;
- /** @internal */
- void itemDropped (const SourceDetails&) override;
- private:
- friend class TreeViewItem;
- class ContentComponent;
- class TreeViewport;
- class InsertPointHighlight;
- class TargetGroupHighlight;
- std::unique_ptr<TreeViewport> viewport;
- CriticalSection nodeAlterationLock;
- TreeViewItem* rootItem = nullptr;
- std::unique_ptr<InsertPointHighlight> dragInsertPointHighlight;
- std::unique_ptr<TargetGroupHighlight> dragTargetGroupHighlight;
- int indentSize = -1;
- bool defaultOpenness = false, needsRecalculating = true, rootItemVisible = true;
- bool multiSelectEnabled = false, openCloseButtonsVisible = true;
- void itemsChanged() noexcept;
- void recalculateIfNeeded();
- void updateButtonUnderMouse (const MouseEvent&);
- struct InsertPoint;
- void showDragHighlight (const InsertPoint&) noexcept;
- void hideDragHighlight() noexcept;
- void handleDrag (const StringArray&, const SourceDetails&);
- void handleDrop (const StringArray&, const SourceDetails&);
- bool toggleOpenSelectedItem();
- void moveOutOfSelectedItem();
- void moveIntoSelectedItem();
- void moveByPages (int numPages);
- #if JUCE_CATCH_DEPRECATED_CODE_MISUSE
- // this method has been deprecated - see the new version..
- virtual int paintOpenCloseButton (Graphics&, int, int, bool) { return 0; }
- #endif
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeView)
- };
- } // namespace juce
|