JUCE-7.0.12-0-g4f43011b96 JUCE-7.0.12-0-g4f43011b96
JUCE — C++ application framework with suport for VST, VST3, LV2 audio plug-ins

« « « Anklang Documentation
Loading...
Searching...
No Matches
juce_PluginListComponent.cpp
Go to the documentation of this file.
1 /*
2 ==============================================================================
3
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
6
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
9
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
12
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
15
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
18
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
22
23 ==============================================================================
24*/
25
26namespace juce
27{
28
30{
31public:
32 TableModel (PluginListComponent& c, KnownPluginList& l) : owner (c), list (l) {}
33
34 int getNumRows() override
35 {
36 return list.getNumTypes() + list.getBlacklistedFiles().size();
37 }
38
39 void paintRowBackground (Graphics& g, int /*rowNumber*/, int /*width*/, int /*height*/, bool rowIsSelected) override
40 {
42 const auto c = rowIsSelected ? defaultColour.interpolatedWith (owner.findColour (ListBox::textColourId), 0.5f)
44
45 g.fillAll (c);
46 }
47
48 enum
49 {
50 nameCol = 1,
51 typeCol = 2,
52 categoryCol = 3,
53 manufacturerCol = 4,
54 descCol = 5
55 };
56
57 void paintCell (Graphics& g, int row, int columnId, int width, int height, bool /*rowIsSelected*/) override
58 {
59 String text;
60 bool isBlacklisted = row >= list.getNumTypes();
61
62 if (isBlacklisted)
63 {
64 if (columnId == nameCol)
65 text = list.getBlacklistedFiles() [row - list.getNumTypes()];
66 else if (columnId == descCol)
67 text = TRANS ("Deactivated after failing to initialise correctly");
68 }
69 else
70 {
71 auto desc = list.getTypes()[row];
72
73 switch (columnId)
74 {
75 case nameCol: text = desc.name; break;
76 case typeCol: text = desc.pluginFormatName; break;
77 case categoryCol: text = desc.category.isNotEmpty() ? desc.category : "-"; break;
78 case manufacturerCol: text = desc.manufacturerName; break;
79 case descCol: text = getPluginDescription (desc); break;
80
81 default: jassertfalse; break;
82 }
83 }
84
85 if (text.isNotEmpty())
86 {
88 g.setColour (isBlacklisted ? Colours::red
89 : columnId == nameCol ? defaultTextColour
90 : defaultTextColour.interpolatedWith (Colours::transparentBlack, 0.3f));
91 g.setFont (Font ((float) height * 0.7f, Font::bold));
92 g.drawFittedText (text, 4, 0, width - 6, height, Justification::centredLeft, 1, 0.9f);
93 }
94 }
95
96 void cellClicked (int rowNumber, int columnId, const juce::MouseEvent& e) override
97 {
99
100 if (rowNumber >= 0 && rowNumber < getNumRows() && e.mods.isPopupMenu())
101 owner.createMenuForRow (rowNumber).showMenuAsync (PopupMenu::Options().withDeletionCheck (owner));
102 }
103
104 void deleteKeyPressed (int) override
105 {
106 owner.removeSelectedPlugins();
107 }
108
110 {
111 switch (newSortColumnId)
112 {
113 case nameCol: list.sort (KnownPluginList::sortAlphabetically, isForwards); break;
114 case typeCol: list.sort (KnownPluginList::sortByFormat, isForwards); break;
115 case categoryCol: list.sort (KnownPluginList::sortByCategory, isForwards); break;
116 case manufacturerCol: list.sort (KnownPluginList::sortByManufacturer, isForwards); break;
117 case descCol: break;
118
119 default: jassertfalse; break;
120 }
121 }
122
123 static String getPluginDescription (const PluginDescription& desc)
124 {
125 StringArray items;
126
127 if (desc.descriptiveName != desc.name)
128 items.add (desc.descriptiveName);
129
130 items.add (desc.version);
131
132 items.removeEmptyStrings();
133 return items.joinIntoString (" - ");
134 }
135
136 PluginListComponent& owner;
137 KnownPluginList& list;
138
140};
141
142//==============================================================================
144{
145public:
148 const String& title, const String& text)
149 : owner (plc),
150 formatToScan (format),
151 filesOrIdentifiersToScan (filesOrIdentifiers),
152 propertiesToUse (properties),
153 pathChooserWindow (TRANS ("Select folders to scan..."), String(), MessageBoxIconType::NoIcon),
154 progressWindow (title, text, MessageBoxIconType::NoIcon),
155 numThreads (threads),
157 {
158 const auto blacklisted = owner.list.getBlacklistedFiles();
159 initiallyBlacklistedFiles = std::set<String> (blacklisted.begin(), blacklisted.end());
160
161 FileSearchPath path (formatToScan.getDefaultLocationsToSearch());
162
163 // You need to use at least one thread when scanning plug-ins asynchronously
164 jassert (! allowAsync || (numThreads > 0));
165
166 // If the filesOrIdentifiersToScan argument isn't empty, we should only scan these
167 // If the path is empty, then paths aren't used for this format.
168 if (filesOrIdentifiersToScan.isEmpty() && path.getNumPaths() > 0)
169 {
170 #if ! JUCE_IOS
171 if (propertiesToUse != nullptr)
172 path = getLastSearchPath (*propertiesToUse, formatToScan);
173 #endif
174
175 pathList.setSize (500, 300);
176 pathList.setPath (path);
177
178 pathChooserWindow.addCustomComponent (&pathList);
179 pathChooserWindow.addButton (TRANS ("Scan"), 1, KeyPress (KeyPress::returnKey));
180 pathChooserWindow.addButton (TRANS ("Cancel"), 0, KeyPress (KeyPress::escapeKey));
181
182 pathChooserWindow.enterModalState (true,
183 ModalCallbackFunction::forComponent (startScanCallback,
184 &pathChooserWindow, this),
185 false);
186 }
187 else
188 {
189 startScan();
190 }
191 }
192
193 ~Scanner() override
194 {
195 if (pool != nullptr)
196 {
197 pool->removeAllJobs (true, 60000);
198 pool.reset();
199 }
200 }
201
202private:
203 PluginListComponent& owner;
204 AudioPluginFormat& formatToScan;
205 StringArray filesOrIdentifiersToScan;
206 PropertiesFile* propertiesToUse;
208 AlertWindow pathChooserWindow, progressWindow;
210 String pluginBeingScanned;
211 double progress = 0;
212 const int numThreads;
213 bool allowAsync, timerReentrancyCheck = false;
214 std::atomic<bool> finished { false };
216 std::set<String> initiallyBlacklistedFiles;
217 ScopedMessageBox messageBox;
218
219 static void startScanCallback (int result, AlertWindow* alert, Scanner* scanner)
220 {
221 if (alert != nullptr && scanner != nullptr)
222 {
223 if (result != 0)
224 scanner->warnUserAboutStupidPaths();
225 else
226 scanner->finishedScan();
227 }
228 }
229
230 // Try to dissuade people from to scanning their entire C: drive, or other system folders.
231 void warnUserAboutStupidPaths()
232 {
233 for (int i = 0; i < pathList.getPath().getNumPaths(); ++i)
234 {
235 auto f = pathList.getPath().getRawString (i);
236
237 if (File::isAbsolutePath (f) && isStupidPath (File (f)))
238 {
240 TRANS ("Plugin Scanning"),
241 TRANS ("If you choose to scan folders that contain non-plugin files, "
242 "then scanning may take a long time, and can cause crashes when "
243 "attempting to load unsuitable files.")
244 + newLine
245 + TRANS ("Are you sure you want to scan the folder \"XYZ\"?")
246 .replace ("XYZ", f),
247 TRANS ("Scan"));
248 messageBox = AlertWindow::showScopedAsync (options, [this] (int result)
249 {
250 if (result != 0)
251 startScan();
252 else
253 finishedScan();
254 });
255
256 return;
257 }
258 }
259
260 startScan();
261 }
262
263 static bool isStupidPath (const File& f)
264 {
267
268 if (roots.contains (f))
269 return true;
270
280
281 for (auto location : pathsThatWouldBeStupidToScan)
282 {
283 auto sillyFolder = File::getSpecialLocation (location);
284
285 if (f == sillyFolder || sillyFolder.isAChildOf (f))
286 return true;
287 }
288
289 return false;
290 }
291
292 void startScan()
293 {
294 pathChooserWindow.setVisible (false);
295
296 scanner.reset (new PluginDirectoryScanner (owner.list, formatToScan, pathList.getPath(),
297 true, owner.deadMansPedalFile, allowAsync));
298
299 if (! filesOrIdentifiersToScan.isEmpty())
300 {
301 scanner->setFilesOrIdentifiersToScan (filesOrIdentifiersToScan);
302 }
303 else if (propertiesToUse != nullptr)
304 {
305 setLastSearchPath (*propertiesToUse, formatToScan, pathList.getPath());
306 propertiesToUse->saveIfNeeded();
307 }
308
309 progressWindow.addButton (TRANS ("Cancel"), 0, KeyPress (KeyPress::escapeKey));
310 progressWindow.addProgressBarComponent (progress);
311 progressWindow.enterModalState();
312
313 if (numThreads > 0)
314 {
315 pool.reset (new ThreadPool (ThreadPoolOptions{}.withNumberOfThreads (numThreads)));
316
317 for (int i = numThreads; --i >= 0;)
318 pool->addJob (new ScanJob (*this), true);
319 }
320
321 startTimer (20);
322 }
323
324 void finishedScan()
325 {
326 const auto blacklisted = owner.list.getBlacklistedFiles();
328
331 initiallyBlacklistedFiles.begin(), initiallyBlacklistedFiles.end(),
333
334 owner.scanFinished (scanner != nullptr ? scanner->getFailedFiles() : StringArray(),
336 }
337
338 void timerCallback() override
339 {
340 if (timerReentrancyCheck)
341 return;
342
343 progress = scanner->getProgress();
344
345 if (pool == nullptr)
346 {
347 const ScopedValueSetter<bool> setter (timerReentrancyCheck, true);
348
349 if (doNextScan())
350 startTimer (20);
351 }
352
353 if (! progressWindow.isCurrentlyModal())
354 finished = true;
355
356 if (finished)
357 finishedScan();
358 else
359 progressWindow.setMessage (TRANS ("Testing") + ":\n\n" + pluginBeingScanned);
360 }
361
362 bool doNextScan()
363 {
364 if (scanner->scanNextFile (true, pluginBeingScanned))
365 return true;
366
367 finished = true;
368 return false;
369 }
370
371 struct ScanJob final : public ThreadPoolJob
372 {
373 ScanJob (Scanner& s) : ThreadPoolJob ("pluginscan"), scanner (s) {}
374
375 JobStatus runJob() override
376 {
377 while (scanner.doNextScan() && ! shouldExit())
378 {}
379
380 return jobHasFinished;
381 }
382
383 Scanner& scanner;
384
386 };
387
389};
390
392{
393 scanFor (format, StringArray());
394}
395
396void PluginListComponent::scanFor (AudioPluginFormat& format, const StringArray& filesOrIdentifiersToScan)
397{
398 currentScanner.reset (new Scanner (*this, format, filesOrIdentifiersToScan, propertiesToUse, allowAsync, numThreads,
399 dialogTitle.isNotEmpty() ? dialogTitle : TRANS ("Scanning for plug-ins..."),
400 dialogText.isNotEmpty() ? dialogText : TRANS ("Searching for all possible plug-in files...")));
401}
402
404{
405 return currentScanner != nullptr;
406}
407
408void PluginListComponent::scanFinished (const StringArray& failedFiles,
410{
412
413 const auto addWarningText = [&warnings] (const auto& range, const auto& prefix)
414 {
415 if (range.size() == 0)
416 return;
417
418 StringArray names;
419
420 for (auto& f : range)
421 names.add (File::createFileWithoutCheckingPath (f).getFileName());
422
423 warnings.add (prefix + ":\n\n" + names.joinIntoString (", "));
424 };
425
426 addWarningText (newBlacklistedFiles, TRANS ("The following files encountered fatal errors during validation"));
427 addWarningText (failedFiles, TRANS ("The following files appeared to be plugin files, but failed to load correctly"));
428
429 currentScanner.reset(); // mustn't delete this before using the failed files array
430
431 if (! warnings.isEmpty())
432 {
434 TRANS ("Scan complete"),
435 warnings.joinIntoString ("\n\n"));
436 messageBox = AlertWindow::showScopedAsync (options, nullptr);
437 }
438}
439
440//==============================================================================
442 const File& deadMansPedal, PropertiesFile* const props,
444 : formatManager (manager),
445 list (listToEdit),
446 deadMansPedalFile (deadMansPedal),
447 optionsButton ("Options..."),
448 propertiesToUse (props),
450 numThreads (allowAsync ? 1 : 0)
451{
452 tableModel.reset (new TableModel (*this, listToEdit));
453
454 TableHeaderComponent& header = table.getHeader();
455
456 header.addColumn (TRANS ("Name"), TableModel::nameCol, 200, 100, 700, TableHeaderComponent::defaultFlags | TableHeaderComponent::sortedForwards);
457 header.addColumn (TRANS ("Format"), TableModel::typeCol, 80, 80, 80, TableHeaderComponent::notResizable);
458 header.addColumn (TRANS ("Category"), TableModel::categoryCol, 100, 100, 200);
459 header.addColumn (TRANS ("Manufacturer"), TableModel::manufacturerCol, 200, 100, 300);
460 header.addColumn (TRANS ("Description"), TableModel::descCol, 300, 100, 500, TableHeaderComponent::notSortable);
461
462 table.setHeaderHeight (22);
463 table.setRowHeight (20);
464 table.setModel (tableModel.get());
465 table.setMultipleSelectionEnabled (true);
466 addAndMakeVisible (table);
467
468 addAndMakeVisible (optionsButton);
469 optionsButton.onClick = [this]
470 {
472 .withDeletionCheck (*this)
473 .withTargetComponent (optionsButton));
474 };
475
476 optionsButton.setTriggeredOnMouseDown (true);
477
478 setSize (400, 600);
479 list.addChangeListener (this);
480 updateList();
481 table.getHeader().reSortTable();
482
484 deadMansPedalFile.deleteFile();
485}
486
491
493{
494 optionsButton.setButtonText (newText);
495 resized();
496}
497
498void PluginListComponent::setScanDialogText (const String& title, const String& content)
499{
500 dialogTitle = title;
501 dialogText = content;
502}
503
505{
506 numThreads = num;
507}
508
510{
511 auto r = getLocalBounds().reduced (2);
512
513 if (optionsButton.isVisible())
514 {
515 optionsButton.setBounds (r.removeFromBottom (24));
516 optionsButton.changeWidthToFitText (24);
517 r.removeFromBottom (3);
518 }
519
520 table.setBounds (r);
521}
522
523void PluginListComponent::changeListenerCallback (ChangeBroadcaster*)
524{
525 table.getHeader().reSortTable();
526 updateList();
527}
528
529void PluginListComponent::updateList()
530{
531 table.updateContent();
532 table.repaint();
533}
534
536{
537 auto selected = table.getSelectedRows();
538
539 for (int i = table.getNumRows(); --i >= 0;)
540 if (selected.contains (i))
541 removePluginItem (i);
542}
543
545{
546 table.setModel (nullptr);
547 tableModel.reset (model);
548 table.setModel (tableModel.get());
549
550 table.getHeader().reSortTable();
551 table.updateContent();
552 table.repaint();
553}
554
555static bool canShowFolderForPlugin (KnownPluginList& list, int index)
556{
557 return File::createFileWithoutCheckingPath (list.getTypes()[index].fileOrIdentifier).exists();
558}
559
560static void showFolderForPlugin (KnownPluginList& list, int index)
561{
562 if (canShowFolderForPlugin (list, index))
563 File (list.getTypes()[index].fileOrIdentifier).revealToUser();
564}
565
566void PluginListComponent::removeMissingPlugins()
567{
568 auto types = list.getTypes();
569
570 for (int i = types.size(); --i >= 0;)
571 {
572 auto type = types.getUnchecked (i);
573
574 if (! formatManager.doesPluginStillExist (type))
575 list.removeType (type);
576 }
577}
578
579void PluginListComponent::removePluginItem (int index)
580{
581 if (index < list.getNumTypes())
582 list.removeType (list.getTypes()[index]);
583 else
584 list.removeFromBlacklist (list.getBlacklistedFiles() [index - list.getNumTypes()]);
585}
586
588{
590 menu.addItem (PopupMenu::Item (TRANS ("Clear list"))
591 .setAction ([this] { list.clear(); }));
592
593 menu.addSeparator();
594
595 for (auto format : formatManager.getFormats())
596 if (format->canScanForPlugins())
597 menu.addItem (PopupMenu::Item ("Remove all " + format->getName() + " plug-ins")
598 .setEnabled (! list.getTypesForFormat (*format).isEmpty())
599 .setAction ([this, format]
600 {
601 for (auto& pd : list.getTypesForFormat (*format))
602 list.removeType (pd);
603 }));
604
605 menu.addSeparator();
606
607 menu.addItem (PopupMenu::Item (TRANS ("Remove selected plug-in from list"))
608 .setEnabled (table.getNumSelectedRows() > 0)
609 .setAction ([this] { removeSelectedPlugins(); }));
610
611 menu.addItem (PopupMenu::Item (TRANS ("Remove any plug-ins whose files no longer exist"))
612 .setAction ([this] { removeMissingPlugins(); }));
613
614 menu.addSeparator();
615
616 auto selectedRow = table.getSelectedRow();
617
618 menu.addItem (PopupMenu::Item (TRANS ("Show folder containing selected plug-in"))
619 .setEnabled (canShowFolderForPlugin (list, selectedRow))
620 .setAction ([this, selectedRow] { showFolderForPlugin (list, selectedRow); }));
621
622 menu.addSeparator();
623
624 for (auto format : formatManager.getFormats())
625 if (format->canScanForPlugins())
626 menu.addItem (PopupMenu::Item ("Scan for new or updated " + format->getName() + " plug-ins")
627 .setAction ([this, format] { scanFor (*format); }));
628
629 return menu;
630}
631
633{
635
636 if (rowNumber >= 0 && rowNumber < tableModel->getNumRows())
637 {
638 menu.addItem (PopupMenu::Item (TRANS ("Remove plug-in from list"))
639 .setAction ([this, rowNumber] { removePluginItem (rowNumber); }));
640
641 menu.addItem (PopupMenu::Item (TRANS ("Show folder containing plug-in"))
642 .setEnabled (canShowFolderForPlugin (list, rowNumber))
643 .setAction ([this, rowNumber] { showFolderForPlugin (list, rowNumber); }));
644 }
645
646 return menu;
647}
648
649bool PluginListComponent::isInterestedInFileDrag (const StringArray& /*files*/)
650{
651 return true;
652}
653
654void PluginListComponent::filesDropped (const StringArray& files, int, int)
655{
657 list.scanAndAddDragAndDroppedFiles (formatManager, files, typesFound);
658}
659
661{
662 auto key = "lastPluginScanPath_" + format.getName();
663
664 if (properties.containsKey (key) && properties.getValue (key, {}).trim().isEmpty())
665 properties.removeValue (key);
666
667 return FileSearchPath (properties.getValue (key, format.getDefaultLocationsToSearch().toString()));
668}
669
671 const FileSearchPath& newPath)
672{
673 auto key = "lastPluginScanPath_" + format.getName();
674
675 if (newPath.getNumPaths() == 0)
676 properties.removeValue (key);
677 else
678 properties.setValue (key, newPath.toString());
679}
680
681} // namespace juce
T back_inserter(T... args)
T begin(T... args)
A window that displays a message and has buttons for the user to react to it.
void addButton(const String &name, int returnValue, const KeyPress &shortcutKey1=KeyPress(), const KeyPress &shortcutKey2=KeyPress())
Adds a button to the window.
void setMessage(const String &message)
Changes the dialog box's message.
static ScopedMessageBox showScopedAsync(const MessageBoxOptions &options, std::function< void(int)> callback)
Shows an alert window using the specified options.
void addProgressBarComponent(double &progressValue, std::optional< ProgressBar::Style > style=std::nullopt)
Adds a progress-bar to the window.
void addCustomComponent(Component *component)
Adds a user-defined component to the dialog box.
Holds a resizable array of primitive or copy-by-value objects.
Definition juce_Array.h:56
This maintains a list of known AudioPluginFormats.
Array< AudioPluginFormat * > getFormats() const
Returns a list of all the registered formats.
bool doesPluginStillExist(const PluginDescription &) const
Checks that the file or component for this plugin actually still exists.
The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc.
virtual FileSearchPath getDefaultLocationsToSearch()=0
Returns the typical places to look for this kind of plugin.
void setButtonText(const String &newText)
Changes the button's text.
void setTriggeredOnMouseDown(bool isTriggeredOnMouseDown) noexcept
Sets whether the button click should happen when the mouse is pressed or released.
std::function< void()> onClick
You can assign a lambda to this callback object to have it called when the button is clicked.
Holds a list of ChangeListeners, and sends messages to them when instructed.
void addChangeListener(ChangeListener *listener)
Registers a listener to receive change callbacks from this broadcaster.
void removeChangeListener(ChangeListener *listener)
Unregisters a listener from the list.
bool isVisible() const noexcept
Tests whether the component is visible or not.
void addAndMakeVisible(Component *child, int zOrder=-1)
Adds a child component to this one, and also makes the child visible if it isn't already.
void setEnabled(bool shouldBeEnabled)
Enables or disables this component.
void repaint()
Marks the whole component as needing to be redrawn.
void setBounds(int x, int y, int width, int height)
Changes the component's position and size.
void setSize(int newWidth, int newHeight)
Changes the size of the component.
void enterModalState(bool takeKeyboardFocus=true, ModalComponentManager::Callback *callback=nullptr, bool deleteWhenDismissed=false)
Puts the component into a modal state.
Colour findColour(int colourID, bool inheritFromParent=false) const
Looks for a colour that has been registered with the given colour ID number.
Rectangle< int > getLocalBounds() const noexcept
Returns the component's bounds, relative to its own origin.
bool isCurrentlyModal(bool onlyConsiderForemostModalComponent=true) const noexcept
Returns true if this component is the modal one.
virtual void setVisible(bool shouldBeVisible)
Makes the component visible or invisible.
Shows a set of file paths in a list, allowing them to be added, removed or re-ordered.
const FileSearchPath & getPath() const noexcept
Returns the path as it is currently shown.
void setPath(const FileSearchPath &newPath)
Changes the current path.
Represents a set of folders that make up a search path.
int getNumPaths() const
Returns the number of folders in this search path.
String getRawString(int index) const
Returns the unaltered text of the folder at the specified index.
Represents a local file or directory.
Definition juce_File.h:45
static bool isAbsolutePath(StringRef path)
Returns true if the string seems to be a fully-specified absolute path.
SpecialLocationType
A set of types of location that can be passed to the getSpecialLocation() method.
Definition juce_File.h:867
@ userMoviesDirectory
The most likely place where a user might store their movie files.
Definition juce_File.h:884
@ userMusicDirectory
The most likely place where a user might store their music files.
Definition juce_File.h:881
@ tempDirectory
The folder that should be used for temporary files.
Definition juce_File.h:919
@ globalApplicationsDirectory
The directory in which applications normally get installed.
Definition juce_File.h:963
@ userDocumentsDirectory
The user's default documents folder.
Definition juce_File.h:875
@ userPicturesDirectory
The most likely place where a user might store their picture files.
Definition juce_File.h:887
@ userDesktopDirectory
The folder that contains the user's desktop objects.
Definition juce_File.h:878
@ userHomeDirectory
The user's home folder.
Definition juce_File.h:869
static void findFileSystemRoots(Array< File > &results)
Creates a set of files to represent each file root.
static File JUCE_CALLTYPE getSpecialLocation(const SpecialLocationType type)
Finds the location of a special type of file or directory, such as a home folder or documents folder.
bool deleteFile() const
Deletes a file.
bool isAChildOf(const File &potentialParentDirectory) const
Checks whether a file is somewhere inside a directory.
static File createFileWithoutCheckingPath(const String &absolutePath) noexcept
Creates a file that simply contains this string, without doing the sanity-checking that the normal co...
Definition juce_File.cpp:31
bool exists() const
Checks whether the file actually exists.
Represents a particular font, including its size, style, etc.
Definition juce_Font.h:42
@ bold
boldens the font.
Definition juce_Font.h:51
A graphics context, used for drawing a component or image.
void drawFittedText(const String &text, int x, int y, int width, int height, Justification justificationFlags, int maximumNumberOfLines, float minimumHorizontalScale=0.0f) const
Tries to draw a text string inside a given space.
void setFont(const Font &newFont)
Changes the font to use for subsequent text-drawing functions.
void setColour(Colour newColour)
Changes the current drawing colour.
void fillAll() const
Fills the context's entire clip region with the current colour or brush.
@ centredLeft
Indicates that the item should be centred vertically but placed on the left hand side.
Represents a key press, including any modifier keys that are needed.
static const int escapeKey
key-code for the escape key
static const int returnKey
key-code for the return key
Manages a list of plugin types.
void sort(SortMethod method, bool forwards)
Sorts the list.
int getNumTypes() const noexcept
Returns the number of types currently in the list.
const StringArray & getBlacklistedFiles() const
Returns the list of blacklisted files.
Array< PluginDescription > getTypes() const
Returns a copy of the current list.
void setMultipleSelectionEnabled(bool shouldBeEnabled) noexcept
Turns on multiple-selection of rows.
void setRowHeight(int newHeight)
Sets the height of each row in the list.
int getSelectedRow(int index=0) const
Returns the row number of a selected row.
@ textColourId
The preferred colour to use for drawing text in the listbox.
@ backgroundColourId
The background colour to fill the list with.
void updateContent()
Causes the list to refresh its content.
int getNumSelectedRows() const
Returns the number of rows that are currently selected.
SparseSet< int > getSelectedRows() const
Returns a sparse set indicating the rows that are currently selected.
static MessageBoxOptions makeOptionsOkCancel(MessageBoxIconType iconType, const String &title, const String &message, const String &button1Text=String(), const String &button2Text=String(), Component *associatedComponent=nullptr)
Creates options suitable for a message box with two buttons.
static MessageBoxOptions makeOptionsOk(MessageBoxIconType iconType, const String &title, const String &message, const String &buttonText=String(), Component *associatedComponent=nullptr)
Creates options suitable for a message box with a single button.
static ModalComponentManager::Callback * forComponent(void(*functionToCall)(int, ComponentType *), ComponentType *component)
This is a utility function to create a ModalComponentManager::Callback that will call a static functi...
bool isPopupMenu() const noexcept
Checks whether the user is trying to launch a pop-up menu.
Contains position and status information about a mouse event.
const ModifierKeys mods
The key modifiers associated with the event.
A small class to represent some facts about a particular type of plug-in.
String name
The name of the plug-in.
String descriptiveName
A more descriptive name for the plug-in.
Scans a directory for plugins, and adds them to a KnownPluginList.
static void applyBlacklistingsFromDeadMansPedal(KnownPluginList &listToApplyTo, const File &deadMansPedalFile)
Reads the given dead-mans-pedal file and applies its contents to the list.
int getNumRows() override
This must return the number of rows currently in the table.
void cellClicked(int rowNumber, int columnId, const juce::MouseEvent &e) override
This callback is made when the user clicks on one of the cells in the table.
void deleteKeyPressed(int) override
Override this to be informed when the delete key is pressed.
void sortOrderChanged(int newSortColumnId, bool isForwards) override
This callback is made when the table's sort order is changed.
void paintCell(Graphics &g, int row, int columnId, int width, int height, bool) override
This must draw one of the cells.
void paintRowBackground(Graphics &g, int, int, int, bool rowIsSelected) override
This must draw the background behind one of the rows in the table.
A component displaying a list of plugins, with options to scan for them, add, remove and sort them.
static FileSearchPath getLastSearchPath(PropertiesFile &, AudioPluginFormat &)
Returns the last search path stored in a given properties file for the specified format.
void setTableModel(TableListBoxModel *)
Sets a custom table model to be used.
~PluginListComponent() override
Destructor.
bool isScanning() const noexcept
Returns true if there's currently a scan in progress.
PopupMenu createOptionsMenu()
Returns a pop-up menu that contains all the options for scanning and updating the list.
void resized() override
Called when this component's size has been changed.
void removeSelectedPlugins()
Removes the plugins currently selected in the table.
PopupMenu createMenuForRow(int rowNumber)
Returns a menu that can be shown if a row is right-clicked, containing actions like "remove plugin" o...
void setNumberOfThreadsForScanning(int numThreads)
Sets how many threads to simultaneously scan for plugins.
static void setLastSearchPath(PropertiesFile &, AudioPluginFormat &, const FileSearchPath &)
Stores a search path in a properties file for the given format.
void setOptionsButtonText(const String &newText)
Changes the text in the panel's options button.
PluginListComponent(AudioPluginFormatManager &formatManager, KnownPluginList &listToRepresent, const File &deadMansPedalFile, PropertiesFile *propertiesToUse, bool allowPluginsWhichRequireAsynchronousInstantiation=false)
Creates the list component.
void scanFor(AudioPluginFormat &)
Triggers an asynchronous scan for the given format.
void setScanDialogText(const String &textForProgressWindowTitle, const String &textForProgressWindowDescription)
Changes the text in the progress dialog box that is shown when scanning.
Class used to create a set of options to pass to the show() method.
Creates and displays a popup-menu.
void showMenuAsync(const Options &options)
Runs the menu asynchronously.
void addItem(Item newItem)
Adds an item to the menu.
Wrapper on a file that stores a list of key/value data pairs.
bool saveIfNeeded()
This will flush all the values to disk if they've changed since the last time they were saved.
String getValue(StringRef keyName, const String &defaultReturnValue=String()) const noexcept
Returns one of the properties as a string.
void setValue(StringRef keyName, const var &value)
Sets a named property.
bool containsKey(StringRef keyName) const noexcept
Returns true if the properties include the given key.
void removeValue(StringRef keyName)
Deletes a property.
Rectangle reduced(ValueType deltaX, ValueType deltaY) const noexcept
Returns a rectangle that is smaller than this one by a given amount.
Objects of this type can be used to programmatically close message boxes.
Helper class providing an RAII-based mechanism for temporarily setting and then re-setting a value.
A special array for holding a list of strings.
String joinIntoString(StringRef separatorString, int startIndex=0, int numberOfElements=-1) const
Joins the strings in the array together into one string.
void removeEmptyStrings(bool removeWhitespaceStrings=true)
Removes empty strings from the array.
int size() const noexcept
Returns the number of strings in the array.
void add(String stringToAdd)
Appends a string at the end of the array.
bool isEmpty() const noexcept
Returns true if the array is empty, false otherwise.
The JUCE String class!
Definition juce_String.h:53
String trim() const
Returns a copy of this string with any whitespace characters removed from the start and end.
bool isEmpty() const noexcept
Returns true if the string contains no characters.
bool isNotEmpty() const noexcept
Returns true if the string contains at least one character.
A component that displays a strip of column headings for a table, and allows these to be resized,...
void reSortTable()
Triggers a re-sort of the table according to the current sort-column.
@ defaultFlags
This set of default flags is used as the default parameter value in addColumn().
@ notSortable
A quick way of combining flags for a column that's not sortable.
@ sortedForwards
If this is set, the column is currently the one by which the table is sorted (forwards).
@ notResizable
A quick way of combining flags for a column that's not resizable.
void addColumn(const String &columnName, int columnId, int width, int minimumWidth=30, int maximumWidth=-1, int propertyFlags=defaultFlags, int insertIndex=-1)
Adds a column to the table.
One of these is used by a TableListBox as the data model for the table's contents.
virtual void cellClicked(int rowNumber, int columnId, const MouseEvent &)
This callback is made when the user clicks on one of the cells in the table.
void setModel(TableListBoxModel *newModel)
Changes the TableListBoxModel that is being used for this table.
void setHeaderHeight(int newHeight)
Changes the height of the table header component.
int getNumRows() override
This has to return the number of items in the list.
TableHeaderComponent & getHeader() const noexcept
Returns the header component being used in this table.
void changeWidthToFitText()
Changes this button's width to fit neatly around its current text, without changing its height.
A task that is executed by a ThreadPool object.
JobStatus
These are the values that can be returned by the runJob() method.
@ jobHasFinished
indicates that the job has finished and can be removed from the pool.
bool shouldExit() const noexcept
Returns true if something is trying to interrupt this job and make it stop.
A set of threads that will run a list of jobs.
Makes repeated callbacks to a virtual method at a specified time interval.
Definition juce_Timer.h:52
void startTimer(int intervalInMilliseconds) noexcept
Starts the timer and sets the length of interval required.
T end(T... args)
#define TRANS(stringLiteral)
Uses the LocalisedStrings class to translate the given string literal.
#define jassert(expression)
Platform-independent assertion macro.
#define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className)
This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for ...
#define jassertfalse
This will always cause an assertion failure.
JUCE Namespace.
NewLine newLine
A predefined object representing a new-line, which can be written to a string or stream.
@ WarningIcon
An exclamation mark to indicate that the dialog is a warning about something and shouldn't be ignored...
@ NoIcon
No icon will be shown on the dialog box.
@ InfoIcon
An icon that indicates that the dialog box is just giving the user some information,...
Type unalignedPointerCast(void *ptr) noexcept
Casts a pointer to another type via void*, which suppresses the cast-align warning which sometimes ar...
Definition juce_Memory.h:88
T reset(T... args)
T set_difference(T... args)
Describes a popup menu item.
Item & setEnabled(bool shouldBeEnabled) &noexcept
Sets the isEnabled flag (and returns a reference to this item to allow chaining).
Item & setAction(std::function< void()> action) &noexcept
Sets the action property (and returns a reference to this item to allow chaining).
A set of threads that will run a list of jobs.
ThreadPoolOptions withNumberOfThreads(int newNumberOfThreads) const
The number of threads to run.