|
- /*
- ==============================================================================
-
- This file is part of the JUCE library - "Jules' Utility Class Extensions"
- Copyright 2004-11 by Raw Material Software Ltd.
-
- ------------------------------------------------------------------------------
-
- JUCE can be redistributed and/or modified under the terms of the GNU General
- Public License (Version 2), as published by the Free Software Foundation.
- A copy of the license is included in the JUCE distribution, or can be found
- online at www.gnu.org/licenses.
-
- JUCE 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.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.rawmaterialsoftware.com/juce for more information.
-
- ==============================================================================
- */
-
- #include "jucer_ProjectTreeViewBase.h"
- #include "../Application/jucer_OpenDocumentManager.h"
-
-
- //==============================================================================
- ProjectTreeViewBase::ProjectTreeViewBase (const Project::Item& item_)
- : item (item_), isFileMissing (false)
- {
- item.getNode().addListener (this);
- }
-
- ProjectTreeViewBase::~ProjectTreeViewBase()
- {
- item.getNode().removeListener (this);
- }
-
- //==============================================================================
- String ProjectTreeViewBase::getDisplayName() const
- {
- return item.getName().toString();
- }
-
- void ProjectTreeViewBase::setName (const String& newName)
- {
- if (item.isMainGroup())
- item.getProject().setTitle (newName);
- else
- item.getName() = newName;
- }
-
- //==============================================================================
- File ProjectTreeViewBase::getFile() const
- {
- return item.getFile();
- }
-
- void ProjectTreeViewBase::browseToAddExistingFiles()
- {
- const File location (item.isGroup() ? item.determineGroupFolder() : getFile());
- FileChooser fc ("Add Files to Jucer Project", location, String::empty, false);
-
- if (fc.browseForMultipleFilesOrDirectories())
- {
- StringArray files;
-
- for (int i = 0; i < fc.getResults().size(); ++i)
- files.add (fc.getResults().getReference(i).getFullPathName());
-
- addFiles (files, 0);
- }
- }
-
- void ProjectTreeViewBase::addFiles (const StringArray& files, int insertIndex)
- {
- ProjectTreeViewBase* p = dynamic_cast <ProjectTreeViewBase*> (getParentItem());
-
- if (p != nullptr)
- p->addFiles (files, insertIndex);
- }
-
- void ProjectTreeViewBase::moveSelectedItemsTo (OwnedArray <Project::Item>& selectedNodes, int insertIndex)
- {
- jassertfalse;
- }
-
- //==============================================================================
- ProjectTreeViewBase* ProjectTreeViewBase::findTreeViewItem (const Project::Item& itemToFind)
- {
- if (item == itemToFind)
- {
- return this;
- }
- else
- {
- const bool wasOpen = isOpen();
- setOpen (true);
-
- for (int i = getNumSubItems(); --i >= 0;)
- {
- ProjectTreeViewBase* pg = dynamic_cast <ProjectTreeViewBase*> (getSubItem(i));
-
- if (pg != nullptr)
- {
- pg = pg->findTreeViewItem (itemToFind);
-
- if (pg != nullptr)
- return pg;
- }
- }
-
- setOpen (wasOpen);
- }
-
- return 0;
- }
-
- //==============================================================================
- void ProjectTreeViewBase::triggerAsyncRename (const Project::Item& itemToRename)
- {
- class RenameMessage : public CallbackMessage
- {
- public:
- RenameMessage (TreeView* const tree_, const Project::Item& itemToRename_)
- : tree (tree_), itemToRename (itemToRename_) {}
-
- void messageCallback()
- {
- if (tree != nullptr)
- {
- ProjectTreeViewBase* pg = dynamic_cast <ProjectTreeViewBase*> (tree->getRootItem());
-
- if (pg != nullptr)
- {
- pg = pg->findTreeViewItem (itemToRename);
-
- if (pg != nullptr)
- pg->showRenameBox();
- }
- }
- }
-
- private:
- Component::SafePointer<TreeView> tree;
- Project::Item itemToRename;
- };
-
- (new RenameMessage (getOwnerView(), itemToRename))->post();
- }
-
- //==============================================================================
- void ProjectTreeViewBase::checkFileStatus()
- {
- const File file (getFile());
- const bool nowMissing = file != File::nonexistent && ! file.exists();
-
- if (nowMissing != isFileMissing)
- {
- isFileMissing = nowMissing;
- repaintItem();
- }
- }
-
- void ProjectTreeViewBase::revealInFinder() const
- {
- getFile().revealToUser();
- }
-
- void ProjectTreeViewBase::deleteItem()
- {
- item.removeItemFromProject();
- }
-
- void ProjectTreeViewBase::deleteAllSelectedItems()
- {
- TreeView* tree = getOwnerView();
- const int numSelected = tree->getNumSelectedItems();
- OwnedArray <File> filesToTrash;
- OwnedArray <Project::Item> itemsToRemove;
-
- int i;
- for (i = 0; i < numSelected; ++i)
- {
- const ProjectTreeViewBase* const p = dynamic_cast <ProjectTreeViewBase*> (tree->getSelectedItem (i));
-
- if (p != nullptr)
- {
- itemsToRemove.add (new Project::Item (p->item));
-
- if (p->getFile().existsAsFile())
- filesToTrash.add (new File (p->getFile()));
- }
- }
-
- if (filesToTrash.size() > 0)
- {
- String fileList;
- const int maxFilesToList = 10;
- for (i = jmin (maxFilesToList, filesToTrash.size()); --i >= 0;)
- fileList << filesToTrash.getUnchecked(i)->getFullPathName() << "\n";
-
- if (filesToTrash.size() > maxFilesToList)
- fileList << "\n...plus " << (filesToTrash.size() - maxFilesToList) << " more files...";
-
- int r = AlertWindow::showYesNoCancelBox (AlertWindow::NoIcon, "Delete Project Items",
- "As well as removing the selected item(s) from the project, do you also want to move their files to the trash:\n\n"
- + fileList,
- "Just remove references",
- "Also move files to Trash",
- "Cancel",
- tree->getTopLevelComponent());
-
- if (r == 0)
- return;
-
- if (r != 2)
- filesToTrash.clear();
- }
-
- ProjectTreeViewBase* treeRootItem = dynamic_cast <ProjectTreeViewBase*> (tree->getRootItem());
- jassert (treeRootItem != nullptr);
-
- if (treeRootItem != nullptr)
- {
- for (i = filesToTrash.size(); --i >= 0;)
- {
- const File f (*filesToTrash.getUnchecked(i));
-
- OpenDocumentManager::getInstance()->closeFile (f, false);
-
- if (! f.moveToTrash())
- {
- // xxx
- }
- }
-
- for (i = itemsToRemove.size(); --i >= 0;)
- {
- ProjectTreeViewBase* itemToRemove = treeRootItem->findTreeViewItem (*itemsToRemove.getUnchecked(i));
-
- if (itemToRemove != nullptr)
- {
- OpenDocumentManager::getInstance()->closeFile (itemToRemove->getFile(), false);
- itemToRemove->deleteItem();
- }
- }
- }
- }
-
- static int indexOfNode (const ValueTree& parent, const ValueTree& child)
- {
- for (int i = parent.getNumChildren(); --i >= 0;)
- if (parent.getChild (i) == child)
- return i;
-
- return -1;
- }
-
- void ProjectTreeViewBase::moveItems (OwnedArray <Project::Item>& selectedNodes,
- Project::Item destNode, int insertIndex)
- {
- int i;
- for (i = selectedNodes.size(); --i >= 0;)
- {
- Project::Item* const n = selectedNodes.getUnchecked(i);
-
- if (destNode == *n || destNode.getNode().isAChildOf (n->getNode())) // Check for recursion.
- return;
-
- if (! destNode.canContain (*n))
- selectedNodes.remove (i);
- }
-
- // Don't include any nodes that are children of other selected nodes..
- for (i = selectedNodes.size(); --i >= 0;)
- {
- Project::Item* const n = selectedNodes.getUnchecked(i);
-
- for (int j = selectedNodes.size(); --j >= 0;)
- {
- if (j != i && n->getNode().isAChildOf (selectedNodes.getUnchecked(j)->getNode()))
- {
- selectedNodes.remove (i);
- break;
- }
- }
- }
-
- // Remove and re-insert them one at a time..
- for (i = 0; i < selectedNodes.size(); ++i)
- {
- Project::Item* selectedNode = selectedNodes.getUnchecked(i);
-
- if (selectedNode->getNode().getParent() == destNode.getNode()
- && indexOfNode (destNode.getNode(), selectedNode->getNode()) < insertIndex)
- --insertIndex;
-
- selectedNode->removeItemFromProject();
- destNode.addChild (*selectedNode, insertIndex++);
- }
- }
-
- //==============================================================================
- bool ProjectTreeViewBase::isInterestedInFileDrag (const StringArray& files)
- {
- return acceptsFileDrop (files);
- }
-
- void ProjectTreeViewBase::filesDropped (const StringArray& files, int insertIndex)
- {
- addFiles (files, insertIndex);
- }
-
- void ProjectTreeViewBase::getAllSelectedNodesInTree (Component* componentInTree, OwnedArray <Project::Item>& selectedNodes)
- {
- TreeView* tree = dynamic_cast <TreeView*> (componentInTree);
-
- if (tree == nullptr)
- tree = componentInTree->findParentComponentOfClass ((TreeView*) 0);
-
- if (tree != nullptr)
- {
- const int numSelected = tree->getNumSelectedItems();
-
- for (int i = 0; i < numSelected; ++i)
- {
- const ProjectTreeViewBase* const p = dynamic_cast <ProjectTreeViewBase*> (tree->getSelectedItem (i));
-
- if (p != nullptr)
- selectedNodes.add (new Project::Item (p->item));
- }
- }
- }
-
- bool ProjectTreeViewBase::isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails)
- {
- if (dragSourceDetails.description != projectItemDragType)
- return false;
-
- OwnedArray <Project::Item> selectedNodes;
- getAllSelectedNodesInTree (dragSourceDetails.sourceComponent, selectedNodes);
-
- return selectedNodes.size() > 0 && acceptsDragItems (selectedNodes);
- }
-
- void ProjectTreeViewBase::itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex)
- {
- OwnedArray <Project::Item> selectedNodes;
- getAllSelectedNodesInTree (dragSourceDetails.sourceComponent, selectedNodes);
-
- if (selectedNodes.size() > 0)
- {
- TreeView* tree = getOwnerView();
- ScopedPointer <XmlElement> oldOpenness (tree->getOpennessState (false));
-
- moveSelectedItemsTo (selectedNodes, insertIndex);
-
- if (oldOpenness != nullptr)
- tree->restoreOpennessState (*oldOpenness, false);
- }
- }
-
- //==============================================================================
- void ProjectTreeViewBase::treeChildrenChanged (const ValueTree& parentTree)
- {
- if (parentTree == item.getNode())
- {
- refreshSubItems();
- treeHasChanged();
- setOpen (true);
- }
- }
-
- void ProjectTreeViewBase::valueTreePropertyChanged (ValueTree& tree, const Identifier& property)
- {
- if (tree == item.getNode())
- repaintItem();
- }
-
- void ProjectTreeViewBase::valueTreeChildAdded (ValueTree& parentTree, ValueTree& childWhichHasBeenAdded)
- {
- treeChildrenChanged (parentTree);
- }
-
- void ProjectTreeViewBase::valueTreeChildRemoved (ValueTree& parentTree, ValueTree& childWhichHasBeenRemoved)
- {
- treeChildrenChanged (parentTree);
- }
-
- void ProjectTreeViewBase::valueTreeChildOrderChanged (ValueTree& parentTree)
- {
- treeChildrenChanged (parentTree);
- }
-
- void ProjectTreeViewBase::valueTreeParentChanged (ValueTree& tree)
- {
- }
-
- //==============================================================================
- bool ProjectTreeViewBase::mightContainSubItems()
- {
- return item.getNumChildren() > 0;
- }
-
- const String ProjectTreeViewBase::getUniqueName() const
- {
- jassert (item.getID().isNotEmpty());
- return item.getID();
- }
-
- void ProjectTreeViewBase::itemOpennessChanged (bool isNowOpen)
- {
- if (isNowOpen)
- refreshSubItems();
- }
-
- void ProjectTreeViewBase::addSubItems()
- {
- for (int i = 0; i < item.getNumChildren(); ++i)
- {
- ProjectTreeViewBase* p = createSubItem (item.getChild(i));
-
- if (p != nullptr)
- addSubItem (p);
- }
- }
-
- void ProjectTreeViewBase::refreshSubItems()
- {
- OpennessRestorer openness (*this);
- clearSubItems();
- addSubItems();
- }
-
- void ProjectTreeViewBase::showMultiSelectionPopupMenu()
- {
- PopupMenu m;
- m.addItem (6, "Delete");
-
- switch (m.show())
- {
- case 6: deleteAllSelectedItems(); break;
- default: break;
- }
- }
-
- void ProjectTreeViewBase::itemDoubleClicked (const MouseEvent& e)
- {
- invokeShowDocument();
- }
-
- class TreeviewItemSelectionTimer : public Timer
- {
- public:
- TreeviewItemSelectionTimer (ProjectTreeViewBase& owner_)
- : owner (owner_)
- {}
-
- void timerCallback()
- {
- owner.invokeShowDocument();
- }
-
- private:
- ProjectTreeViewBase& owner;
-
- JUCE_DECLARE_NON_COPYABLE (TreeviewItemSelectionTimer);
- };
-
- void ProjectTreeViewBase::itemSelectionChanged (bool isNowSelected)
- {
- if (isNowSelected)
- {
- delayedSelectionTimer = new TreeviewItemSelectionTimer (*this);
-
- // for images, give the user longer to start dragging before assuming they're
- // clicking to select it for previewing..
- delayedSelectionTimer->startTimer (item.isImageFile() ? 250 : 120);
- }
- else
- {
- delayedSelectionTimer = nullptr;
- }
- }
-
- const String ProjectTreeViewBase::getTooltip()
- {
- return String::empty;
- }
-
- const var ProjectTreeViewBase::getDragSourceDescription()
- {
- delayedSelectionTimer = nullptr;
- return projectItemDragType;
- }
-
- void ProjectTreeViewBase::invokeShowDocument()
- {
- delayedSelectionTimer = nullptr;
- showDocument();
- }
-
- //==============================================================================
- ProjectTreeViewBase* ProjectTreeViewBase::getParentProjectItem() const
- {
- return dynamic_cast <ProjectTreeViewBase*> (getParentItem());
- }
-
- ProjectContentComponent* ProjectTreeViewBase::getProjectContentComponent() const
- {
- Component* c = getOwnerView();
-
- while (c != nullptr)
- {
- ProjectContentComponent* pcc = dynamic_cast <ProjectContentComponent*> (c);
-
- if (pcc != nullptr)
- return pcc;
-
- c = c->getParentComponent();
- }
-
- return 0;
- }
|