1 /* 2 * aTunes 3 * Copyright (C) Alex Aranda, Sylvain Gaudard and contributors 4 * 5 * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors 6 * 7 * http://www.atunes.org 8 * http://sourceforge.net/projects/atunes 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 package net.sourceforge.atunes.kernel.modules.repository; 22 23 import java.io.File; 24 import java.util.ArrayList; 25 import java.util.Collection; 26 import java.util.Collections; 27 import java.util.HashMap; 28 import java.util.List; 29 import java.util.Map; 30 31 import net.sourceforge.atunes.kernel.AbstractHandler; 32 import net.sourceforge.atunes.model.IAlbum; 33 import net.sourceforge.atunes.model.IArtist; 34 import net.sourceforge.atunes.model.IAudioFilesRemovedListener; 35 import net.sourceforge.atunes.model.IAudioObject; 36 import net.sourceforge.atunes.model.IBackgroundWorker; 37 import net.sourceforge.atunes.model.IBackgroundWorkerFactory; 38 import net.sourceforge.atunes.model.IDialogFactory; 39 import net.sourceforge.atunes.model.IFavoritesHandler; 40 import net.sourceforge.atunes.model.IFileManager; 41 import net.sourceforge.atunes.model.IFolder; 42 import net.sourceforge.atunes.model.IGenre; 43 import net.sourceforge.atunes.model.IIndeterminateProgressDialog; 44 import net.sourceforge.atunes.model.ILocalAudioObject; 45 import net.sourceforge.atunes.model.IMessageDialog; 46 import net.sourceforge.atunes.model.INavigationHandler; 47 import net.sourceforge.atunes.model.IRepository; 48 import net.sourceforge.atunes.model.IRepositoryHandler; 49 import net.sourceforge.atunes.model.IRepositoryTransaction; 50 import net.sourceforge.atunes.model.IStateRepository; 51 import net.sourceforge.atunes.model.IStateService; 52 import net.sourceforge.atunes.model.IStatisticsHandler; 53 import net.sourceforge.atunes.model.ITaskService; 54 import net.sourceforge.atunes.model.ITrackInfo; 55 import net.sourceforge.atunes.model.IUnknownObjectChecker; 56 import net.sourceforge.atunes.model.IYear; 57 import net.sourceforge.atunes.model.ViewMode; 58 import net.sourceforge.atunes.utils.CollectionUtils; 59 import net.sourceforge.atunes.utils.I18nUtils; 60 import net.sourceforge.atunes.utils.Logger; 61 import net.sourceforge.atunes.utils.StringUtils; 62 63 /** 64 * The repository handler. 65 */ 66 public final class RepositoryHandler extends AbstractHandler implements 67 IRepositoryHandler { 68 69 private boolean caseSensitiveTrees; 70 71 private boolean storeRatingInFile; 72 73 private IStatisticsHandler statisticsHandler; 74 75 private INavigationHandler navigationHandler; 76 77 private IStateService stateService; 78 79 private IRepository repository; 80 81 private RepositoryAutoRefresher repositoryRefresher; 82 83 /** Listeners notified when an audio file is removed */ 84 private final List<IAudioFilesRemovedListener> audioFilesRemovedListeners = new ArrayList<IAudioFilesRemovedListener>(); 85 86 private IFavoritesHandler favoritesHandler; 87 88 private IRepositoryTransaction transaction; 89 90 private IStateRepository stateRepository; 91 92 private IBackgroundWorkerFactory backgroundWorkerFactory; 93 94 private IDialogFactory dialogFactory; 95 96 private List<File> foldersSelectedFromPreferences; 97 98 private IUnknownObjectChecker unknownObjectChecker; 99 100 private IFileManager fileManager; 101 102 private RepositoryReader currentRepositoryReader; 103 104 private ITaskService taskService; 105 106 private boolean repositoryNotSelected; 107 108 /** 109 * @param taskService 110 */ setTaskService(final ITaskService taskService)111 public void setTaskService(final ITaskService taskService) { 112 this.taskService = taskService; 113 } 114 115 /** 116 * @param fileManager 117 */ setFileManager(final IFileManager fileManager)118 public void setFileManager(final IFileManager fileManager) { 119 this.fileManager = fileManager; 120 } 121 122 /** 123 * @param unknownObjectChecker 124 */ setUnknownObjectChecker( final IUnknownObjectChecker unknownObjectChecker)125 public void setUnknownObjectChecker( 126 final IUnknownObjectChecker unknownObjectChecker) { 127 this.unknownObjectChecker = unknownObjectChecker; 128 } 129 130 /** 131 * @param dialogFactory 132 */ setDialogFactory(final IDialogFactory dialogFactory)133 public void setDialogFactory(final IDialogFactory dialogFactory) { 134 this.dialogFactory = dialogFactory; 135 } 136 137 /** 138 * @param backgroundWorkerFactory 139 */ setBackgroundWorkerFactory( final IBackgroundWorkerFactory backgroundWorkerFactory)140 public void setBackgroundWorkerFactory( 141 final IBackgroundWorkerFactory backgroundWorkerFactory) { 142 this.backgroundWorkerFactory = backgroundWorkerFactory; 143 } 144 145 /** 146 * @param stateRepository 147 */ setStateRepository(final IStateRepository stateRepository)148 public void setStateRepository(final IStateRepository stateRepository) { 149 this.stateRepository = stateRepository; 150 } 151 152 /** 153 * @param repository 154 */ setRepository(final IRepository repository)155 void setRepository(final IRepository repository) { 156 this.repository = repository; 157 setRepositoryNotSelected(repository == null 158 || (repository instanceof VoidRepository)); 159 } 160 161 /** 162 * @param favoritesHandler 163 */ setFavoritesHandler(final IFavoritesHandler favoritesHandler)164 public void setFavoritesHandler(final IFavoritesHandler favoritesHandler) { 165 this.favoritesHandler = favoritesHandler; 166 } 167 168 /** 169 * @param stateService 170 */ setStateService(final IStateService stateService)171 public void setStateService(final IStateService stateService) { 172 this.stateService = stateService; 173 } 174 175 /** 176 * @param statisticsHandler 177 */ setStatisticsHandler(final IStatisticsHandler statisticsHandler)178 public void setStatisticsHandler(final IStatisticsHandler statisticsHandler) { 179 this.statisticsHandler = statisticsHandler; 180 } 181 182 /** 183 * @param navigationHandler 184 */ setNavigationHandler(final INavigationHandler navigationHandler)185 public void setNavigationHandler(final INavigationHandler navigationHandler) { 186 this.navigationHandler = navigationHandler; 187 } 188 189 /** 190 * @param repositoryRefresher 191 */ setRepositoryRefresher( final RepositoryAutoRefresher repositoryRefresher)192 public void setRepositoryRefresher( 193 final RepositoryAutoRefresher repositoryRefresher) { 194 this.repositoryRefresher = repositoryRefresher; 195 } 196 197 @Override applicationStateChanged()198 public void applicationStateChanged() { 199 // User changed repository folders 200 if (this.foldersSelectedFromPreferences != null) { 201 this.currentRepositoryReader = getBean(RepositoryReader.class); 202 this.currentRepositoryReader 203 .newRepositoryWithFolders(this.foldersSelectedFromPreferences); 204 this.foldersSelectedFromPreferences = null; 205 } else if (checkPropertiesToTrackForReload()) { 206 reloadRepository(); 207 } 208 // Reschedule repository refresher 209 this.repositoryRefresher.start(); 210 } 211 212 @Override initHandler()213 protected void initHandler() { 214 // Initially use void repository until one is loaded or selected 215 this.repository = getBean(VoidRepository.class); 216 217 setPropertiesToTrackForReload(); 218 219 // Add itself as listener 220 addAudioFilesRemovedListener(this); 221 } 222 setPropertiesToTrackForReload()223 private void setPropertiesToTrackForReload() { 224 // A change in these properties needs a repository reload 225 this.caseSensitiveTrees = this.stateRepository 226 .isKeyAlwaysCaseSensitiveInRepositoryStructure(); 227 this.storeRatingInFile = this.stateRepository.isStoreRatingInFile(); 228 } 229 checkPropertiesToTrackForReload()230 private boolean checkPropertiesToTrackForReload() { 231 boolean reload = false; 232 // Check properties and return true if needs to reload repository 233 // Update properties to keep track or further changes 234 if (this.caseSensitiveTrees != this.stateRepository 235 .isKeyAlwaysCaseSensitiveInRepositoryStructure()) { 236 reload = true; 237 this.caseSensitiveTrees = this.stateRepository 238 .isKeyAlwaysCaseSensitiveInRepositoryStructure(); 239 } 240 if (this.storeRatingInFile != this.stateRepository 241 .isStoreRatingInFile()) { 242 reload = true; 243 this.storeRatingInFile = this.stateRepository.isStoreRatingInFile(); 244 } 245 246 return reload; 247 } 248 249 @Override addAudioObjectsAndRefresh(final List<ILocalAudioObject> result)250 public void addAudioObjectsAndRefresh(final List<ILocalAudioObject> result) { 251 getBean(AddFilesToRepositoryTask.class) 252 .execute(this.repository, result); 253 } 254 255 /** 256 * Finish. 257 */ 258 @Override applicationFinish()259 public void applicationFinish() { 260 this.repositoryRefresher.stop(); 261 if (!isRepositoryVoid()) { 262 // Only store repository if it's dirty 263 if (transactionPending()) { 264 this.stateService.persistRepositoryCache(this.repository); 265 } else { 266 Logger.info("Repository is clean"); 267 } 268 269 // Execute command after last access to repository 270 new LoadRepositoryCommandExecutor().execute(this.stateRepository 271 .getCommandAfterAccessRepository()); 272 } 273 } 274 275 @Override getFolders()276 public List<File> getFolders() { 277 return this.repository.getRepositoryFolders(); 278 } 279 280 @Override getAlbums()281 public List<IAlbum> getAlbums() { 282 List<IAlbum> result = new ArrayList<IAlbum>(); 283 Collection<IArtist> artists = this.repository.getArtists(); 284 for (IArtist a : artists) { 285 result.addAll(a.getAlbums().values()); 286 } 287 Collections.sort(result); 288 return result; 289 } 290 291 @Override getArtists()292 public List<IArtist> getArtists() { 293 List<IArtist> result = new ArrayList<IArtist>(); 294 result.addAll(this.repository.getArtists()); 295 Collections.sort(result); 296 return result; 297 } 298 299 @Override getArtist(final String name)300 public IArtist getArtist(final String name) { 301 return this.repository.getArtist(name); 302 } 303 304 @Override removeArtist(final IArtist artist)305 public void removeArtist(final IArtist artist) { 306 this.repository.removeArtist(artist); 307 } 308 309 @Override getGenre(final String genre)310 public IGenre getGenre(final String genre) { 311 return this.repository.getGenre(genre); 312 } 313 314 @Override removeGenre(final IGenre genre)315 public void removeGenre(final IGenre genre) { 316 this.repository.removeGenre(genre); 317 } 318 319 @Override getFileIfLoaded(final String fileName)320 public ILocalAudioObject getFileIfLoaded(final String fileName) { 321 return this.repository.getFile(fileName); 322 } 323 324 @Override getFoldersCount()325 public int getFoldersCount() { 326 return this.repository.getRepositoryFolders().size(); 327 } 328 329 @Override getRepositoryFolderContainingFile(final ILocalAudioObject file)330 public File getRepositoryFolderContainingFile(final ILocalAudioObject file) { 331 for (File folder : this.repository.getRepositoryFolders()) { 332 if (file.getUrl().startsWith( 333 net.sourceforge.atunes.utils.FileUtils.getPath(folder))) { 334 return folder; 335 } 336 } 337 return null; 338 } 339 340 @Override getRepositoryPath()341 public String getRepositoryPath() { 342 // TODO: Remove this method as now more than one folder can be added to 343 // repository 344 return this.repository.getRepositoryFolders().size() > 0 ? net.sourceforge.atunes.utils.FileUtils 345 .getPath(this.repository.getRepositoryFolders().get(0)) : ""; 346 } 347 348 @Override getRepositoryTotalSize()349 public long getRepositoryTotalSize() { 350 return this.repository.getTotalSizeInBytes(); 351 } 352 353 @Override getNumberOfFiles()354 public int getNumberOfFiles() { 355 return this.repository.countFiles(); 356 } 357 358 @Override getAudioFilesList()359 public Collection<ILocalAudioObject> getAudioFilesList() { 360 return this.repository.getFiles(); 361 } 362 363 @Override getAudioFilesForAlbums( final List<IAlbum> albums)364 public List<ILocalAudioObject> getAudioFilesForAlbums( 365 final List<IAlbum> albums) { 366 List<ILocalAudioObject> result = new ArrayList<ILocalAudioObject>(); 367 for (IAlbum album : albums) { 368 result.addAll(album.getAudioObjects()); 369 } 370 return result; 371 } 372 373 @Override getAudioFilesForArtists( final List<IArtist> artists)374 public List<ILocalAudioObject> getAudioFilesForArtists( 375 final List<IArtist> artists) { 376 List<ILocalAudioObject> result = new ArrayList<ILocalAudioObject>(); 377 for (IArtist artist : artists) { 378 result.addAll(artist.getAudioObjects()); 379 } 380 return result; 381 } 382 383 @Override isRepository(final File folder)384 public boolean isRepository(final File folder) { 385 String path = net.sourceforge.atunes.utils.FileUtils.getPath(folder); 386 for (File folders : this.repository.getRepositoryFolders()) { 387 if (path.startsWith(net.sourceforge.atunes.utils.FileUtils 388 .getPath(folders))) { 389 return true; 390 } 391 } 392 return false; 393 } 394 395 @Override notifyCancel()396 public void notifyCancel() { 397 if (this.currentRepositoryReader != null) { 398 this.currentRepositoryReader.notifyCancel(); 399 } 400 this.currentRepositoryReader = null; 401 } 402 403 @Override refreshFiles(final List<ILocalAudioObject> files)404 public void refreshFiles(final List<ILocalAudioObject> files) { 405 startTransaction(); 406 LocalAudioObjectRefresher refresher = getBean(LocalAudioObjectRefresher.class); 407 for (ILocalAudioObject file : files) { 408 refresher.refreshFile(this.repository, file); 409 } 410 endTransaction(); 411 } 412 413 @Override refreshFolders(final List<IFolder> folders)414 public void refreshFolders(final List<IFolder> folders) { 415 getBean(RefreshFoldersTask.class).execute(this.repository, folders); 416 } 417 418 @Override refreshRepository()419 public void refreshRepository() { 420 if (!isRepositoryVoid()) { 421 this.currentRepositoryReader = getBean(RepositoryReader.class); 422 this.currentRepositoryReader.refresh(this.repository); 423 } 424 } 425 426 @Override reloadRepository()427 public void reloadRepository() { 428 if (!isRepositoryVoid()) { 429 this.dialogFactory.newDialog(IMessageDialog.class).showMessage( 430 I18nUtils.getString("RELOAD_REPOSITORY_MESSAGE")); 431 this.currentRepositoryReader = getBean(RepositoryReader.class); 432 this.currentRepositoryReader 433 .newRepositoryWithFoldersReloaded(this.repository 434 .getRepositoryFolders()); 435 } 436 } 437 438 @Override removeFolders(final List<IFolder> foldersToRemove)439 public void removeFolders(final List<IFolder> foldersToRemove) { 440 startTransaction(); 441 removeFoldersInsideTransaction(foldersToRemove); 442 endTransaction(); 443 } 444 removeFoldersInsideTransaction( final List<IFolder> foldersToRemove)445 private void removeFoldersInsideTransaction( 446 final List<IFolder> foldersToRemove) { 447 if (foldersToRemove == null || foldersToRemove.isEmpty()) { 448 return; 449 } 450 451 for (IFolder folder : foldersToRemove) { 452 453 // Remove content 454 remove(folder.getAudioObjects()); 455 456 // Remove from model 457 if (folder.getParentFolder() != null) { 458 folder.getParentFolder().removeFolder(folder); 459 } 460 } 461 } 462 463 @Override remove(final List<ILocalAudioObject> filesToRemove)464 public void remove(final List<ILocalAudioObject> filesToRemove) { 465 if (filesToRemove == null || filesToRemove.isEmpty()) { 466 return; 467 } 468 469 startTransaction(); 470 removeInsideTransaction(filesToRemove); 471 endTransaction(); 472 } 473 removeInsideTransaction( final List<ILocalAudioObject> filesToRemove)474 private void removeInsideTransaction( 475 final List<ILocalAudioObject> filesToRemove) { 476 RepositoryRemover remover = getBean(RepositoryRemover.class); 477 for (ILocalAudioObject fileToRemove : filesToRemove) { 478 remover.deleteFile(fileToRemove); 479 } 480 481 // Notify listeners 482 for (IAudioFilesRemovedListener listener : this.audioFilesRemovedListeners) { 483 listener.audioFilesRemoved(filesToRemove); 484 } 485 } 486 487 @Override rename(final ILocalAudioObject audioFile, final String name)488 public void rename(final ILocalAudioObject audioFile, final String name) { 489 String oldName = this.fileManager.getPath(audioFile); 490 if (this.fileManager.rename(audioFile, name)) { 491 startTransaction(); 492 this.repository.removeFile(oldName); 493 this.repository.putFile(audioFile); 494 endTransaction(); 495 this.navigationHandler.repositoryReloaded(); 496 this.statisticsHandler.updateFileName(audioFile, oldName, 497 this.fileManager.getPath(audioFile)); 498 } 499 } 500 501 /** 502 * Returns if Repository is void (not yet loaded or selected) 503 * 504 * @return 505 */ isRepositoryVoid()506 private boolean isRepositoryVoid() { 507 return this.repository instanceof VoidRepository; 508 } 509 510 @Override addFolderToRepository()511 public boolean addFolderToRepository() { 512 this.currentRepositoryReader = getBean(RepositoryReader.class); 513 return this.currentRepositoryReader 514 .addFolderToRepository(this.repository); 515 } 516 517 @Override addAudioFilesRemovedListener( final IAudioFilesRemovedListener listener)518 public void addAudioFilesRemovedListener( 519 final IAudioFilesRemovedListener listener) { 520 this.audioFilesRemovedListeners.add(listener); 521 } 522 523 @Override audioFilesRemoved(final List<ILocalAudioObject> audioFiles)524 public void audioFilesRemoved(final List<ILocalAudioObject> audioFiles) { 525 // Update status bar 526 getBean(ShowRepositoryDataHelper.class).showRepositoryAudioFileNumber( 527 getAudioFilesList().size(), getRepositoryTotalSize(), 528 this.repository.getTotalDurationInSeconds()); 529 } 530 531 @Override doInBackground()532 public void doInBackground() { 533 if (this.currentRepositoryReader != null) { 534 this.currentRepositoryReader.doInBackground(); 535 } 536 } 537 538 /** 539 * Returns <code>true</code>if there is a loader reading or refreshing 540 * repository 541 * 542 * @return 543 */ isLoaderWorking()544 protected boolean isLoaderWorking() { 545 return this.currentRepositoryReader != null 546 && this.currentRepositoryReader.isWorking(); 547 } 548 549 @Override repositoryChanged(final IRepository repository)550 public void repositoryChanged(final IRepository repository) { 551 getBean(PersistRepositoryTask.class).persist(repository); 552 this.favoritesHandler.updateFavoritesAfterRepositoryChange(repository); 553 } 554 startTransaction()555 protected final void startTransaction() { 556 this.transaction = new RepositoryTransaction(this.repository, this); 557 } 558 endTransaction()559 protected final void endTransaction() { 560 if (this.transaction != null) { 561 this.transaction.finishTransaction(); 562 } 563 } 564 transactionPending()565 private boolean transactionPending() { 566 return this.transaction != null && this.transaction.isPending(); 567 } 568 569 @Override getDataForView(final ViewMode viewMode)570 public Map<String, ?> getDataForView(final ViewMode viewMode) { 571 return viewMode.getDataForView(this.repository); 572 } 573 574 @Override getFile(final String fileName)575 public ILocalAudioObject getFile(final String fileName) { 576 return this.repository.getFile(fileName); 577 } 578 579 @Override getYear(final String year)580 public IYear getYear(final String year) { 581 return this.repository.getYear(year); 582 } 583 584 @Override removeYear(final IYear year)585 public void removeYear(final IYear year) { 586 this.repository.removeYear(year, this.unknownObjectChecker); 587 } 588 589 @Override removeFile(final ILocalAudioObject file)590 public void removeFile(final ILocalAudioObject file) { 591 this.repository.removeFile(file); 592 this.repository.removeSizeInBytes(this.fileManager.getFileSize(file)); 593 this.repository.removeDurationInSeconds(file.getDuration()); 594 } 595 596 @Override getFolder(final String path)597 public IFolder getFolder(final String path) { 598 return this.repository.getFolder(path); 599 } 600 601 @Override getAudioObjectsByTitle( final String artistName, final List<String> titlesList)602 public List<ILocalAudioObject> getAudioObjectsByTitle( 603 final String artistName, final List<String> titlesList) { 604 if (StringUtils.isEmpty(artistName)) { 605 throw new IllegalArgumentException("Invalid artist name"); 606 } 607 List<ILocalAudioObject> result = new ArrayList<ILocalAudioObject>(); 608 IArtist artist = getArtist(artistName); 609 if (artist != null) { 610 Map<String, ILocalAudioObject> normalizedTitles = getNormalizedAudioObjectsTitles(artist); 611 for (String title : titlesList) { 612 String normalizedTitle = title.toLowerCase(); 613 if (normalizedTitles.containsKey(normalizedTitle)) { 614 result.add(normalizedTitles.get(normalizedTitle)); 615 } 616 } 617 } 618 return result; 619 } 620 621 @Override checkAvailability(final String artist, final List<ITrackInfo> tracks)622 public void checkAvailability(final String artist, 623 final List<ITrackInfo> tracks) { 624 if (StringUtils.isEmpty(artist)) { 625 throw new IllegalArgumentException("Invalid artist name"); 626 } 627 if (!CollectionUtils.isEmpty(tracks)) { 628 IArtist a = getArtist(artist); 629 if (a != null) { 630 Map<String, ILocalAudioObject> normalizedTitles = getNormalizedAudioObjectsTitles(a); 631 for (ITrackInfo track : tracks) { 632 track.setAvailable(normalizedTitles.containsKey(track 633 .getTitle().toLowerCase())); 634 } 635 } 636 } 637 } 638 639 /** 640 * 641 * @param artist 642 * @return 643 */ getNormalizedAudioObjectsTitles( final IArtist artist)644 private Map<String, ILocalAudioObject> getNormalizedAudioObjectsTitles( 645 final IArtist artist) { 646 List<ILocalAudioObject> audioObjects = artist.getAudioObjects(); 647 Map<String, ILocalAudioObject> titles = new HashMap<String, ILocalAudioObject>(); 648 for (ILocalAudioObject lao : audioObjects) { 649 if (lao.getTitle() != null) { 650 titles.put(lao.getTitle().toLowerCase(), lao); // Do lower case 651 // for a better 652 // match 653 } 654 } 655 return titles; 656 } 657 658 @Override importFolders(final List<File> folders, final String path)659 public void importFolders(final List<File> folders, final String path) { 660 final IIndeterminateProgressDialog indeterminateDialog = this.dialogFactory 661 .newDialog(IIndeterminateProgressDialog.class); 662 indeterminateDialog.setTitle(StringUtils.getString( 663 I18nUtils.getString("READING_FILES_TO_IMPORT"), "...")); 664 665 IBackgroundWorker<List<ILocalAudioObject>, Void> worker = this.backgroundWorkerFactory 666 .getWorker(); 667 worker.setActionsBeforeBackgroundStarts(new ShowIndeterminateDialogRunnable( 668 indeterminateDialog)); 669 ImportFoldersToRepositoryCallable callable = getBean(ImportFoldersToRepositoryCallable.class); 670 callable.setFolders(folders); 671 worker.setBackgroundActions(callable); 672 ImportFoldersToRepositoryActionsWithBackgroundResult actionsWhenDone = getBean(ImportFoldersToRepositoryActionsWithBackgroundResult.class); 673 actionsWhenDone.setFolders(folders); 674 actionsWhenDone.setPath(path); 675 actionsWhenDone.setIndeterminateDialog(indeterminateDialog); 676 worker.setActionsWhenDone(actionsWhenDone); 677 worker.execute(this.taskService); 678 } 679 680 @Override setRepositoryFolders(final List<File> folders)681 public void setRepositoryFolders(final List<File> folders) { 682 this.foldersSelectedFromPreferences = folders; 683 } 684 685 @Override folderMoved(final IFolder sourceFolder, final File destination)686 public void folderMoved(final IFolder sourceFolder, final File destination) { 687 startTransaction(); 688 removeFoldersInsideTransaction(Collections.singletonList(sourceFolder)); 689 getBean(RepositoryAddService.class) 690 .addFoldersToRepositoryInsideTransaction(this.repository, 691 Collections.singletonList(destination)); 692 getBean(ShowRepositoryDataHelper.class).showRepositoryAudioFileNumber( 693 this.repository.getFiles().size(), 694 this.repository.getTotalSizeInBytes(), 695 this.repository.getTotalDurationInSeconds()); 696 endTransaction(); 697 } 698 699 @Override getAudioObjectIfLoaded(final IAudioObject ao)700 public IAudioObject getAudioObjectIfLoaded(final IAudioObject ao) { 701 if (ao instanceof ILocalAudioObject) { 702 IAudioObject cachedAO = getFileIfLoaded(ao.getUrl()); 703 if (cachedAO != null) { 704 return cachedAO; 705 } 706 } 707 return ao; 708 } 709 710 /** 711 * Called when repository read 712 */ notifyRepositoryRead()713 void notifyRepositoryRead() { 714 this.currentRepositoryReader = null; 715 } 716 717 @Override existsArtist(final IArtist artist)718 public boolean existsArtist(final IArtist artist) { 719 if (artist != null) { 720 return this.repository.getArtist(artist.getName()) != null; 721 } 722 return false; 723 } 724 725 @Override existsArtist(final String artist)726 public boolean existsArtist(final String artist) { 727 return this.repository.getArtist(artist) != null; 728 } 729 730 @Override existsAlbum(final IAlbum album)731 public boolean existsAlbum(final IAlbum album) { 732 if (album != null) { 733 IArtist artist = this.repository.getArtist(album.getArtist() 734 .getName()); 735 if (artist != null) { 736 if (artist.getAlbum(album.getName()) != null) { 737 return true; 738 } 739 } 740 } 741 return false; 742 } 743 744 @Override existsAlbum(final String artistName, final String album)745 public boolean existsAlbum(final String artistName, final String album) { 746 IArtist artist = this.repository.getArtist(artistName); 747 if (artist != null) { 748 if (artist.getAlbum(album) != null) { 749 return true; 750 } 751 } 752 return false; 753 } 754 755 @Override existsFile(final ILocalAudioObject ao)756 public boolean existsFile(final ILocalAudioObject ao) { 757 return getFileIfLoaded(ao.getUrl()) != null; 758 } 759 760 @Override isRepositoryNotSelected()761 public boolean isRepositoryNotSelected() { 762 return this.repositoryNotSelected; 763 } 764 setRepositoryNotSelected(final boolean notSelected)765 protected void setRepositoryNotSelected(final boolean notSelected) { 766 this.repositoryNotSelected = notSelected; 767 // Force navigation view refresh to show information about repository 768 // not selected 769 this.navigationHandler.refreshCurrentView(); 770 } 771 } 772