Changeset View
Changeset View
Standalone View
Standalone View
wallpapers/image/image.cpp
1 | /*************************************************************************** | 1 | /*************************************************************************** | ||
---|---|---|---|---|---|
2 | * Copyright 2007 Paolo Capriotti <p.capriotti@gmail.com> * | 2 | * Copyright 2007 Paolo Capriotti <p.capriotti@gmail.com> * | ||
3 | * Copyright 2007 Aaron Seigo <aseigo@kde.org> * | 3 | * Copyright 2007 Aaron Seigo <aseigo@kde.org> * | ||
4 | * Copyright 2008 Petri Damsten <damu@iki.fi> * | 4 | * Copyright 2008 Petri Damsten <damu@iki.fi> * | ||
5 | * Copyright 2008 Alexis Ménard <darktears31@gmail.com> * | 5 | * Copyright 2008 Alexis Ménard <darktears31@gmail.com> * | ||
6 | * Copyright 2014 Sebastian Kügler <sebas@kde.org> * | 6 | * Copyright 2014 Sebastian Kügler <sebas@kde.org> * | ||
7 | * Copyright 2015 Kai Uwe Broulik <kde@privat.broulik.de> * | 7 | * Copyright 2015 Kai Uwe Broulik <kde@privat.broulik.de> * | ||
8 | * Copyright 2019 David Redondo <kde@david-redondo.de> * | ||||
8 | * * | 9 | * * | ||
9 | * This program is free software; you can redistribute it and/or modify * | 10 | * This program is free software; you can redistribute it and/or modify * | ||
10 | * it under the terms of the GNU General Public License as published by * | 11 | * it under the terms of the GNU General Public License as published by * | ||
11 | * the Free Software Foundation; either version 2 of the License, or * | 12 | * the Free Software Foundation; either version 2 of the License, or * | ||
12 | * (at your option) any later version. * | 13 | * (at your option) any later version. * | ||
13 | * * | 14 | * * | ||
14 | * This program is distributed in the hope that it will be useful, * | 15 | * This program is distributed in the hope that it will be useful, * | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
Show All 33 Lines | |||||
49 | #include <KNewStuff3/KNS3/DownloadDialog> | 50 | #include <KNewStuff3/KNS3/DownloadDialog> | ||
50 | #include <klocalizedstring.h> | 51 | #include <klocalizedstring.h> | ||
51 | 52 | | |||
52 | #include <Plasma/Theme> | 53 | #include <Plasma/Theme> | ||
53 | #include <Plasma/PluginLoader> | 54 | #include <Plasma/PluginLoader> | ||
54 | #include <qstandardpaths.h> | 55 | #include <qstandardpaths.h> | ||
55 | #include "backgroundlistmodel.h" | 56 | #include "backgroundlistmodel.h" | ||
56 | #include "slidemodel.h" | 57 | #include "slidemodel.h" | ||
58 | #include "slidefiltermodel.h" | ||||
57 | 59 | | |||
58 | #include <KPackage/PackageLoader> | 60 | #include <KPackage/PackageLoader> | ||
59 | 61 | | |||
60 | Image::Image(QObject *parent) | 62 | Image::Image(QObject *parent) | ||
61 | : QObject(parent), | 63 | : QObject(parent), | ||
62 | m_ready(false), | 64 | m_ready(false), | ||
63 | m_delay(10), | 65 | m_delay(10), | ||
64 | m_dirWatch(new KDirWatch(this)), | 66 | m_dirWatch(new KDirWatch(this)), | ||
65 | m_mode(SingleImage), | 67 | m_mode(SingleImage), | ||
68 | m_slideshowMode(Random), | ||||
66 | m_currentSlide(-1), | 69 | m_currentSlide(-1), | ||
67 | m_model(nullptr), | 70 | m_model(nullptr), | ||
68 | m_slideshowModel(nullptr), | 71 | m_slideshowModel(new SlideModel(this, this)), | ||
72 | m_slideFilterModel(new SlideFilterModel(this)), | ||||
69 | m_dialog(nullptr) | 73 | m_dialog(nullptr) | ||
70 | { | 74 | { | ||
71 | m_wallpaperPackage = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Wallpaper/Images")); | 75 | m_wallpaperPackage = KPackage::PackageLoader::self()->loadPackage(QStringLiteral("Wallpaper/Images")); | ||
72 | 76 | | |||
73 | connect(&m_timer, &QTimer::timeout, this, &Image::nextSlide); | 77 | connect(&m_timer, &QTimer::timeout, this, &Image::nextSlide); | ||
74 | 78 | | |||
75 | connect(m_dirWatch, &KDirWatch::created, this, &Image::pathCreated); | 79 | connect(m_dirWatch, &KDirWatch::created, this, &Image::pathCreated); | ||
76 | connect(m_dirWatch, &KDirWatch::dirty, this, &Image::pathDirty); | 80 | connect(m_dirWatch, &KDirWatch::dirty, this, &Image::pathDirty); | ||
77 | connect(m_dirWatch, &KDirWatch::deleted, this, &Image::pathDeleted); | 81 | connect(m_dirWatch, &KDirWatch::deleted, this, &Image::pathDeleted); | ||
78 | m_dirWatch->startScan(); | 82 | m_dirWatch->startScan(); | ||
79 | 83 | | |||
84 | m_slideFilterModel->setSourceModel(m_slideshowModel); | ||||
85 | connect(this, &Image::uncheckedSlidesChanged, m_slideFilterModel, &SlideFilterModel::invalidateFilter); | ||||
86 | | ||||
80 | useSingleImageDefaults(); | 87 | useSingleImageDefaults(); | ||
88 | | ||||
81 | } | 89 | } | ||
82 | 90 | | |||
83 | Image::~Image() | 91 | Image::~Image() | ||
84 | { | 92 | { | ||
85 | delete m_dialog; | 93 | delete m_dialog; | ||
86 | } | 94 | } | ||
87 | 95 | | |||
88 | void Image::classBegin() | 96 | void Image::classBegin() | ||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Line(s) | 152 | if (m_mode == SlideShow) { | |||
151 | updateDirWatch(m_slidePaths); | 159 | updateDirWatch(m_slidePaths); | ||
152 | updateDirWatch(m_slidePaths); | 160 | updateDirWatch(m_slidePaths); | ||
153 | } else { | 161 | } else { | ||
154 | // we need to reset the preferred image | 162 | // we need to reset the preferred image | ||
155 | setSingleImage(); | 163 | setSingleImage(); | ||
156 | } | 164 | } | ||
157 | } | 165 | } | ||
158 | 166 | | |||
167 | Image::SlideshowMode Image::slideshowMode() const | ||||
168 | { | ||||
169 | return m_slideshowMode; | ||||
170 | } | ||||
171 | | ||||
172 | void Image::setSlideshowMode(Image::SlideshowMode mode) | ||||
173 | { | ||||
174 | if (mode == m_slideshowMode) { | ||||
175 | return; | ||||
176 | } | ||||
177 | m_slideshowMode = mode; | ||||
178 | m_slideFilterModel->setSortingMode(mode); | ||||
179 | m_slideFilterModel->sort(0); | ||||
180 | if (m_mode == SlideShow) { | ||||
181 | startSlideshow(); | ||||
182 | } | ||||
183 | emit slideshowModeChanged(); | ||||
184 | } | ||||
185 | | ||||
159 | float distance(const QSize& size, const QSize& desired) | 186 | float distance(const QSize& size, const QSize& desired) | ||
160 | { | 187 | { | ||
161 | // compute difference of areas | 188 | // compute difference of areas | ||
162 | float desiredAspectRatio = ( desired.height() > 0 ) ? desired.width() / (float)desired.height() : 0; | 189 | float desiredAspectRatio = ( desired.height() > 0 ) ? desired.width() / (float)desired.height() : 0; | ||
163 | float candidateAspectRatio = ( size.height() > 0 ) ? size.width() / (float)size.height() : FLT_MAX; | 190 | float candidateAspectRatio = ( size.height() > 0 ) ? size.width() / (float)size.height() : FLT_MAX; | ||
164 | 191 | | |||
165 | float delta = size.width() - desired.width(); | 192 | float delta = size.width() - desired.width(); | ||
166 | delta = (delta >= 0.0 ? delta : -delta*2 ); // Penalize for scaling up | 193 | delta = (delta >= 0.0 ? delta : -delta*2 ); // Penalize for scaling up | ||
▲ Show 20 Lines • Show All 105 Lines • ▼ Show 20 Line(s) | 295 | if (!m_model) { | |||
272 | 299 | | |||
273 | m_model = new BackgroundListModel(this, this); | 300 | m_model = new BackgroundListModel(this, this); | ||
274 | m_model->reload(m_usersWallpapers); | 301 | m_model->reload(m_usersWallpapers); | ||
275 | } | 302 | } | ||
276 | 303 | | |||
277 | return m_model; | 304 | return m_model; | ||
278 | } | 305 | } | ||
279 | 306 | | |||
280 | QAbstractItemModel* Image::slideshowModel() | 307 | QAbstractItemModel * Image::slideFilterModel() { | ||
281 | { | 308 | return m_slideFilterModel; | ||
282 | if (!m_slideshowModel) { | | |||
283 | m_slideshowModel = new SlideModel(this, this); | | |||
284 | m_slideshowModel->reload(m_slidePaths); | | |||
285 | } | | |||
286 | return m_slideshowModel; | | |||
287 | } | 309 | } | ||
288 | | ||||
289 | int Image::slideTimer() const | 310 | int Image::slideTimer() const | ||
290 | { | 311 | { | ||
291 | return m_delay; | 312 | return m_delay; | ||
292 | } | 313 | } | ||
293 | 314 | | |||
294 | void Image::setSlideTimer(int time) | 315 | void Image::setSlideTimer(int time) | ||
295 | { | 316 | { | ||
296 | if (time == m_delay) { | 317 | if (time == m_delay) { | ||
▲ Show 20 Lines • Show All 244 Lines • ▼ Show 20 Line(s) | 550 | } else { | |||
541 | return; | 562 | return; | ||
542 | } | 563 | } | ||
543 | 564 | | |||
544 | if (setAsCurrent) { | 565 | if (setAsCurrent) { | ||
545 | setWallpaper(path); | 566 | setWallpaper(path); | ||
546 | } else { | 567 | } else { | ||
547 | if (m_mode != SingleImage) { | 568 | if (m_mode != SingleImage) { | ||
548 | // it's a slide show, add it to the slide show | 569 | // it's a slide show, add it to the slide show | ||
549 | m_slideshowBackgrounds.append(path); | 570 | m_slideshowModel->addBackground(path); | ||
550 | m_unseenSlideshowBackgrounds.append(path); | | |||
551 | } | 571 | } | ||
552 | // always add it to the user papers, though | 572 | // always add it to the user papers, though | ||
553 | addUsersWallpaper(path); | 573 | addUsersWallpaper(path); | ||
554 | } | 574 | } | ||
555 | } | 575 | } | ||
556 | 576 | | |||
557 | void Image::setWallpaperRetrieved(KJob *job) | 577 | void Image::setWallpaperRetrieved(KJob *job) | ||
558 | { | 578 | { | ||
Show All 12 Lines | |||||
571 | } | 591 | } | ||
572 | 592 | | |||
573 | void Image::setWallpaper(const QString &path) | 593 | void Image::setWallpaper(const QString &path) | ||
574 | { | 594 | { | ||
575 | if (m_mode == SingleImage) { | 595 | if (m_mode == SingleImage) { | ||
576 | m_wallpaper = path; | 596 | m_wallpaper = path; | ||
577 | setSingleImage(); | 597 | setSingleImage(); | ||
578 | } else { | 598 | } else { | ||
579 | m_slideshowBackgrounds.append(path); | 599 | m_wallpaper = path; | ||
580 | m_unseenSlideshowBackgrounds.clear(); | 600 | m_slideshowModel->addBackground(path); | ||
davidedmundson: what will happen if you add a background that the slideFilterModel then filters out? | |||||
Currently the slideshow would restart. I guess we could check here if the index is -1. Or alternatively don't trigger this from the qml side if the image is unchecked. In my mind this even better because then we enable the apply button, too. davidre: Currently the slideshow would restart. I guess we could check here if the index is -1. Or… | |||||
IMHO, here must be checked because it is transparent to the QML code and lets room for failure. msdobrescu: IMHO, here must be checked because it is transparent to the QML code and lets room for failure.
| |||||
581 | m_currentSlide = m_slideshowBackgrounds.size() - 2; | 601 | m_currentSlide = m_slideFilterModel->indexOf(path) - 1; | ||
582 | nextSlide(); | 602 | nextSlide(); | ||
583 | } | 603 | } | ||
584 | //addUsersWallpaper(path); | 604 | //addUsersWallpaper(path); | ||
585 | } | 605 | } | ||
586 | 606 | | |||
587 | void Image::startSlideshow() | 607 | void Image::startSlideshow() | ||
588 | { | 608 | { | ||
589 | if (!m_ready) { | 609 | if (!m_ready || m_slideFilterModel->property("usedInConfig").toBool()) { | ||
590 | return; | 610 | return; | ||
591 | } | 611 | } | ||
592 | | ||||
593 | if(m_findToken.isEmpty()) { | | |||
594 | // populate background list | 612 | // populate background list | ||
595 | m_timer.stop(); | 613 | m_timer.stop(); | ||
596 | m_slideshowBackgrounds.clear(); | 614 | m_slideshowModel->reload(m_slidePaths); | ||
597 | m_unseenSlideshowBackgrounds.clear(); | 615 | connect(m_slideshowModel, &SlideModel::done, this, &Image::backgroundsFound); | ||
598 | BackgroundFinder *finder = new BackgroundFinder(this, m_dirs); | | |||
599 | m_findToken = finder->token(); | | |||
600 | connect(finder, &BackgroundFinder::backgroundsFound, this, &Image::backgroundsFound); | | |||
601 | finder->start(); | | |||
602 | //TODO: what would be cool: paint on the wallpaper itself a busy widget and perhaps some text | 616 | //TODO: what would be cool: paint on the wallpaper itself a busy widget and perhaps some text | ||
603 | //about loading wallpaper slideshow while the thread runs | 617 | //about loading wallpaper slideshow while the thread runs | ||
604 | } else { | | |||
605 | m_scanDirty = true; | | |||
606 | } | | |||
607 | } | 618 | } | ||
608 | 619 | | |||
609 | void Image::backgroundsFound(const QStringList &paths, const QString &token) | 620 | void Image::backgroundsFound() | ||
610 | { | 621 | { | ||
611 | if (token != m_findToken) { | 622 | disconnect(m_slideshowModel, &SlideModel::done, this, 0); | ||
612 | return; | | |||
613 | } | | |||
614 | | ||||
615 | m_findToken.clear(); | | |||
616 | 623 | | |||
617 | if(m_scanDirty) { | 624 | if(m_scanDirty) { | ||
618 | m_scanDirty = false; | 625 | m_scanDirty = false; | ||
619 | startSlideshow(); | 626 | startSlideshow(); | ||
620 | return; | 627 | return; | ||
621 | } | 628 | } | ||
622 | m_slideshowBackgrounds = paths; | 629 | | ||
623 | for(const QString &slide : qAsConst(m_uncheckedSlides)) { | | |||
624 | m_slideshowBackgrounds.removeAll(QUrl(slide).path()); | | |||
625 | } | | |||
626 | m_unseenSlideshowBackgrounds.clear(); | | |||
627 | // start slideshow | 630 | // start slideshow | ||
628 | if (m_slideshowBackgrounds.isEmpty()) { | 631 | if (m_slideFilterModel->rowCount() == 0) { | ||
629 | // no image has been found, which is quite weird... try again later (this is useful for events which | 632 | // no image has been found, which is quite weird... try again later (this is useful for events which | ||
630 | // are not detected by KDirWatch, like a NFS directory being mounted) | 633 | // are not detected by KDirWatch, like a NFS directory being mounted) | ||
631 | QTimer::singleShot(1000, this, &Image::startSlideshow); | 634 | QTimer::singleShot(1000, this, &Image::startSlideshow); | ||
632 | } else { | 635 | } else { | ||
636 | if (m_currentSlide == -1 && m_slideshowMode != Random) { | ||||
637 | m_currentSlide = m_slideFilterModel->indexOf(m_wallpaper) - 1; | ||||
638 | } else { | ||||
633 | m_currentSlide = -1; | 639 | m_currentSlide = -1; | ||
640 | } | ||||
641 | m_slideFilterModel->sort(0); | ||||
634 | nextSlide(); | 642 | nextSlide(); | ||
635 | m_timer.start(m_delay * 1000); | 643 | m_timer.start(m_delay * 1000); | ||
636 | } | 644 | } | ||
637 | } | 645 | } | ||
638 | 646 | | |||
639 | void Image::getNewWallpaper(QQuickItem *ctx) | 647 | void Image::getNewWallpaper(QQuickItem *ctx) | ||
640 | { | 648 | { | ||
641 | if (!m_newStuffDialog) { | 649 | if (!m_newStuffDialog) { | ||
▲ Show 20 Lines • Show All 112 Lines • ▼ Show 20 Line(s) | 760 | if (!m_usersWallpapers.contains(wallpaper)) { | |||
754 | cfg.writeEntry("usersWallpapers", m_usersWallpapers); | 762 | cfg.writeEntry("usersWallpapers", m_usersWallpapers); | ||
755 | cfg.sync(); | 763 | cfg.sync(); | ||
756 | emit usersWallpapersChanged(); | 764 | emit usersWallpapersChanged(); | ||
757 | } | 765 | } | ||
758 | } | 766 | } | ||
759 | 767 | | |||
760 | void Image::nextSlide() | 768 | void Image::nextSlide() | ||
761 | { | 769 | { | ||
762 | if (!m_ready || m_slideshowBackgrounds.isEmpty()) { | 770 | if (!m_ready || m_slideFilterModel->rowCount() == 0) { | ||
763 | return; | 771 | return; | ||
764 | } | 772 | } | ||
765 | 773 | int previousSlide = m_currentSlide; | |||
766 | QString previousPath; | 774 | QUrl previousPath = m_slideFilterModel->index(m_currentSlide, 0).data(BackgroundListModel::PathRole).toUrl(); | ||
767 | if (m_currentSlide > -1 && m_currentSlide < m_unseenSlideshowBackgrounds.size()) { | 775 | if (m_currentSlide == m_slideFilterModel->rowCount() - 1 || m_currentSlide < 0) { | ||
768 | previousPath = m_unseenSlideshowBackgrounds.takeAt(m_currentSlide); | 776 | m_currentSlide = 0; | ||
769 | } | 777 | } else { | ||
770 | 778 | m_currentSlide += 1; | |||
771 | if (m_unseenSlideshowBackgrounds.isEmpty()) { | | |||
772 | m_unseenSlideshowBackgrounds = m_slideshowBackgrounds; | | |||
773 | | ||||
774 | // We're filling the queue again, make sure we can't pick up again | | |||
775 | // the last one picked from the previous set | | |||
776 | if (!previousPath.isEmpty()) { | | |||
777 | m_unseenSlideshowBackgrounds.removeAll(previousPath); | | |||
778 | | ||||
779 | // prevent empty list | | |||
780 | if (m_unseenSlideshowBackgrounds.isEmpty()) { | | |||
781 | m_unseenSlideshowBackgrounds = m_slideshowBackgrounds; | | |||
782 | } | 779 | } | ||
780 | //We are starting again - avoid having the same random order when we restart the slideshow | ||||
781 | if (m_slideshowMode == Random && previousSlide == m_slideFilterModel->rowCount() - 1) { | ||||
782 | m_slideFilterModel->invalidate(); | ||||
783 | } | 783 | } | ||
784 | QUrl next = m_slideFilterModel->index(m_currentSlide, 0).data(BackgroundListModel::PathRole).toUrl(); | ||||
785 | // And avoid showing the same picture twice | ||||
786 | if (previousSlide == m_slideFilterModel->rowCount() - 1 && previousPath == next && m_slideFilterModel->rowCount() > 1) { | ||||
787 | m_currentSlide += 1; | ||||
788 | next = m_slideFilterModel->index(m_currentSlide, 0).data(BackgroundListModel::PathRole).toUrl(); | ||||
784 | } | 789 | } | ||
785 | | ||||
786 | m_currentSlide = KRandom::random() % m_unseenSlideshowBackgrounds.size(); | | |||
787 | const QString currentPath = m_unseenSlideshowBackgrounds.at(m_currentSlide); | | |||
788 | | ||||
789 | m_wallpaperPackage.setPath(currentPath); | | |||
790 | findPreferedImageInPackage(m_wallpaperPackage); | | |||
791 | | ||||
792 | m_timer.stop(); | 790 | m_timer.stop(); | ||
793 | m_timer.start(m_delay * 1000); | 791 | m_timer.start(m_delay * 1000); | ||
794 | 792 | if (next.isEmpty()) { | |||
795 | QString current = m_wallpaperPackage.filePath("preferred"); | 793 | m_wallpaperPath = previousPath.toLocalFile(); | ||
796 | if (current.isEmpty()) { | | |||
797 | m_wallpaperPath = currentPath; | | |||
798 | } else { | 794 | } else { | ||
799 | m_wallpaperPath = current; | 795 | m_wallpaperPath = next.toLocalFile(); | ||
800 | } | 796 | } | ||
801 | | ||||
802 | Q_EMIT wallpaperPathChanged(); | 797 | Q_EMIT wallpaperPathChanged(); | ||
803 | } | 798 | } | ||
804 | 799 | | |||
805 | void Image::openSlide() | 800 | void Image::openSlide() | ||
806 | { | 801 | { | ||
807 | if (!m_wallpaperPackage.isValid()) { | 802 | if (!m_wallpaperPackage.isValid()) { | ||
808 | return; | 803 | return; | ||
809 | } | 804 | } | ||
810 | 805 | | |||
811 | // open in image viewer | 806 | // open in image viewer | ||
812 | QUrl filepath(m_wallpaperPackage.filePath("preferred")); | 807 | QUrl filepath(m_wallpaperPackage.filePath("preferred")); | ||
813 | qCDebug(IMAGEWALLPAPER) << "opening file " << filepath.path(); | 808 | qCDebug(IMAGEWALLPAPER) << "opening file " << filepath.path(); | ||
814 | new KRun(filepath, nullptr); | 809 | new KRun(filepath, nullptr); | ||
815 | } | 810 | } | ||
816 | 811 | | |||
817 | void Image::pathCreated(const QString &path) | 812 | void Image::pathCreated(const QString &path) | ||
818 | { | 813 | { | ||
819 | if(!m_slideshowBackgrounds.contains(path)) { | 814 | if(m_slideshowModel->indexOf(path) == -1) { | ||
820 | QFileInfo fileInfo(path); | 815 | QFileInfo fileInfo(path); | ||
821 | if(fileInfo.isFile() && BackgroundFinder::isAcceptableSuffix(fileInfo.suffix())) { | 816 | if(fileInfo.isFile() && BackgroundFinder::isAcceptableSuffix(fileInfo.suffix())) { | ||
822 | m_slideshowBackgrounds.append(path); | 817 | m_slideshowModel->addBackground(path); | ||
823 | m_unseenSlideshowBackgrounds.append(path); | 818 | if(m_slideFilterModel->rowCount() == 1) { | ||
824 | if(m_slideshowBackgrounds.count() == 1) { | | |||
825 | nextSlide(); | 819 | nextSlide(); | ||
826 | } | 820 | } | ||
827 | } | 821 | } | ||
828 | } | 822 | } | ||
829 | } | 823 | } | ||
830 | 824 | | |||
831 | void Image::pathDeleted(const QString &path) | 825 | void Image::pathDeleted(const QString &path) | ||
832 | { | 826 | { | ||
833 | if(m_slideshowBackgrounds.removeAll(path)) { | 827 | if(m_slideshowModel->indexOf(path) != -1) { | ||
834 | m_unseenSlideshowBackgrounds.removeAll(path); | 828 | m_slideshowModel->removeBackground(path); | ||
835 | if(path == m_img) { | 829 | if(path == m_img) { | ||
836 | nextSlide(); | 830 | nextSlide(); | ||
837 | } | 831 | } | ||
838 | } | 832 | } | ||
839 | } | 833 | } | ||
840 | 834 | | |||
841 | //FIXME: we have to save the configuration also when the dialog cancel button is clicked. | 835 | //FIXME: we have to save the configuration also when the dialog cancel button is clicked. | ||
842 | void Image::removeWallpaper(QString name) | 836 | void Image::removeWallpaper(QString name) | ||
▲ Show 20 Lines • Show All 87 Lines • Show Last 20 Lines |
what will happen if you add a background that the slideFilterModel then filters out?