Changeset View
Changeset View
Standalone View
Standalone View
src/context/ContextView.cpp
Show All 11 Lines | |||||
12 | * PARTICULAR PURPOSE. See the GNU General Public License for more details. * | 12 | * PARTICULAR PURPOSE. See the GNU General Public License for more details. * | ||
13 | * * | 13 | * * | ||
14 | * You should have received a copy of the GNU General Public License along with * | 14 | * You should have received a copy of the GNU General Public License along with * | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. * | 15 | * this program. If not, see <http://www.gnu.org/licenses/>. * | ||
16 | ****************************************************************************************/ | 16 | ****************************************************************************************/ | ||
17 | 17 | | |||
18 | #define DEBUG_PREFIX "ContextView" | 18 | #define DEBUG_PREFIX "ContextView" | ||
19 | 19 | | |||
20 | /* | | |||
21 | Significant parts of this code is inspired and/or copied from KDE plasma sources, | | |||
22 | available at kdebase/workspace/plasma | | |||
23 | */ | | |||
24 | | ||||
25 | #include "ContextView.h" | 20 | #include "ContextView.h" | ||
26 | 21 | | |||
27 | #include <config.h> | 22 | #include "AppletLoader.h" | ||
28 | 23 | #include "AppletModel.h" | |||
29 | #include "Context.h" | 24 | #include "PaletteHandler.h" | ||
30 | #include "ContextScene.h" | 25 | #include "SvgHandler.h" | ||
31 | #include "Svg.h" | | |||
32 | #include "Theme.h" | | |||
33 | #include "amarokconfig.h" | | |||
34 | #include "amarokurls/AmarokUrlHandler.h" | 26 | #include "amarokurls/AmarokUrlHandler.h" | ||
35 | #include "amarokurls/ContextUrlRunner.h" | 27 | #include "amarokurls/ContextUrlRunner.h" | ||
36 | #include "core/support/Amarok.h" | 28 | #include "core/support/Amarok.h" | ||
37 | #include "core/support/Debug.h" | 29 | #include "core/support/Debug.h" | ||
38 | #include "core/meta/Meta.h" | 30 | #include "core/meta/Meta.h" | ||
39 | #include "EngineController.h" | | |||
40 | 31 | | |||
41 | #include <plasma/dataenginemanager.h> | 32 | #include <QDesktopServices> | ||
33 | #include <QFile> | ||||
34 | #include <QGuiApplication> | ||||
35 | #include <QQmlContext> | ||||
36 | #include <QQmlError> | ||||
37 | #include <QQmlPropertyMap> | ||||
38 | #include <QQuickWindow> | ||||
39 | #include <QScreen> | ||||
40 | | ||||
41 | #include <KDeclarative/KDeclarative> | ||||
42 | #include <KI18n/KLocalizedContext> | ||||
43 | #include <KIconThemes/KIconLoader> | ||||
44 | #include <KPackage/PackageLoader> | ||||
42 | 45 | | |||
43 | #include <Phonon/AudioOutput> | | |||
44 | #include <QParallelAnimationGroup> | | |||
45 | #include <QSequentialAnimationGroup> | | |||
46 | #include <QWheelEvent> | | |||
47 | 46 | | |||
48 | namespace Context | 47 | class FontFilter : public QObject | ||
49 | { | 48 | { | ||
49 | Q_OBJECT | ||||
50 | 50 | | |||
51 | class ViewPrivate | | |||
52 | { | | |||
53 | public: | 51 | public: | ||
54 | ViewPrivate(QGraphicsView *view, int uniqueId) | 52 | FontFilter( QObject *parent ) | ||
55 | : q(view), | 53 | : QObject( parent ) | ||
56 | containment(0), | | |||
57 | drawWallpaper(true), | | |||
58 | trackChanges(true), | | |||
59 | viewId(0), | | |||
60 | lastScreen(-1), | | |||
61 | lastDesktop(-2) | | |||
62 | { | 54 | { | ||
63 | if (uniqueId > s_maxViewId) { | 55 | qApp->installEventFilter( this ); | ||
64 | s_maxViewId = uniqueId; | | |||
65 | viewId = uniqueId; | | |||
66 | } | 56 | } | ||
67 | 57 | | |||
68 | if (viewId == 0) { | 58 | bool eventFilter( QObject *watched, QEvent *event ) | ||
69 | // we didn't get a sane value assigned to us, so lets | | |||
70 | // grab the next available id | | |||
71 | viewId = ++s_maxViewId; | | |||
72 | } | | |||
73 | } | | |||
74 | | ||||
75 | ~ViewPrivate() | | |||
76 | { | 59 | { | ||
77 | } | 60 | if( watched == qApp ) | ||
78 | | ||||
79 | void updateSceneRect() | | |||
80 | { | 61 | { | ||
81 | if (!containment || !trackChanges) { | 62 | if( event->type() == QEvent::ApplicationFontChange ) | ||
82 | return; | 63 | emit fontChanged(); | ||
83 | } | | |||
84 | | ||||
85 | kDebug() << "!!!!!!!!!!!!!!!!! setting the scene rect to" | | |||
86 | << containment->sceneBoundingRect() | | |||
87 | << "associated screen is" << containment->screen(); | | |||
88 | | ||||
89 | emit q->sceneRectAboutToChange(); | | |||
90 | if (q->transform().isIdentity()) { //we're not zoomed out | | |||
91 | q->setSceneRect(containment->sceneBoundingRect()); | | |||
92 | } else { | | |||
93 | q->ensureVisible(containment->sceneBoundingRect()); | | |||
94 | } | 64 | } | ||
95 | emit q->sceneRectChanged(); | 65 | return QObject::eventFilter( watched, event ); | ||
96 | } | 66 | } | ||
97 | 67 | | |||
98 | void containmentDestroyed() | 68 | signals: | ||
99 | { | 69 | void fontChanged(); | ||
100 | containment = 0; | 70 | }; | ||
101 | } | | |||
102 | 71 | | |||
103 | void containmentScreenChanged(int wasScreen, int newScreen, Plasma::Containment *containment) | | |||
104 | { | | |||
105 | lastScreen = newScreen; | | |||
106 | lastDesktop = this->containment->desktop(); | | |||
107 | } | | |||
108 | 72 | | |||
109 | void initGraphicsView() | 73 | namespace Context | ||
110 | { | 74 | { | ||
111 | q->setFrameShape(QFrame::NoFrame); | | |||
112 | q->setAutoFillBackground(true); | | |||
113 | q->setDragMode(QGraphicsView::NoDrag); | | |||
114 | q->setInteractive(true); | | |||
115 | q->setAcceptDrops(true); | | |||
116 | q->setAlignment(Qt::AlignLeft | Qt::AlignTop); | | |||
117 | q->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | | |||
118 | q->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); | | |||
119 | } | | |||
120 | | ||||
121 | QGraphicsView *q; | | |||
122 | Plasma::Containment *containment; | | |||
123 | bool drawWallpaper; | | |||
124 | bool trackChanges; | | |||
125 | int viewId; | | |||
126 | int lastScreen; | | |||
127 | int lastDesktop; | | |||
128 | static int s_maxViewId; | | |||
129 | }; | | |||
130 | 75 | | |||
131 | ContextView* ContextView::s_self = 0; | 76 | ContextView* ContextView::s_self = Q_NULLPTR; | ||
132 | 77 | | |||
133 | 78 | | |||
134 | ContextView::ContextView( Plasma::Containment *cont, Plasma::Corona *corona, QWidget* parent ) | 79 | ContextView::ContextView( QWidget *parent ) | ||
135 | : QGraphicsView(parent), | 80 | : QQuickWidget( parent ) | ||
136 | , m_curState( Home ) | 81 | , m_urlRunner( Q_NULLPTR ) | ||
137 | , m_urlRunner(0) | 82 | , m_loader( new AppletLoader( this ) ) | ||
138 | , m_appletExplorer(0) | 83 | , m_appletModel( new AppletModel( m_loader, this ) ) | ||
139 | , m_collapseAnimations(0) | 84 | , m_proxyModel( new AppletProxyModel( m_appletModel, this ) ) | ||
140 | , m_queuedAnimations(0) | 85 | , m_fontFilter( new FontFilter( this ) ) | ||
141 | , m_collapseGroupTimer(0) | 86 | , m_smallSpacing( 2 ) | ||
142 | , d(new ViewPrivate(this, 0)) | 87 | , m_largeSpacing( 8 ) | ||
88 | , m_iconSizes( new QQmlPropertyMap( this ) ) | ||||
143 | { | 89 | { | ||
144 | Q_UNUSED( corona ) | | |||
145 | DEBUG_BLOCK | 90 | DEBUG_BLOCK | ||
146 | 91 | | |||
147 | // using QGraphicsScene::BspTreeIndex leads to crashes in some Qt versions | 92 | KDeclarative::KDeclarative decl; | ||
148 | scene()->setItemIndexMethod( QGraphicsScene::NoIndex ); | 93 | decl.setDeclarativeEngine( engine() ); | ||
149 | //TODO: Figure out a way to use rubberband and ScrollHandDrag | 94 | decl.setupBindings(); | ||
150 | //setDragMode( QGraphicsView::RubberBandDrag ); | 95 | | ||
151 | setTransformationAnchor( QGraphicsView::NoAnchor ); | 96 | connect( this, &QQuickWidget::statusChanged, this, &ContextView::slotStatusChanged ); | ||
152 | setCacheMode( QGraphicsView::CacheBackground ); | 97 | connect( qApp, &QGuiApplication::primaryScreenChanged, this, &ContextView::updateDevicePixelRatio ); | ||
153 | setInteractive( true ); | 98 | connect( m_fontFilter, &FontFilter::fontChanged, this, &ContextView::updateSpacing ); | ||
154 | setAcceptDrops( true ); | 99 | connect( KIconLoader::global(), &KIconLoader::iconLoaderSettingsChanged, this, &ContextView::iconLoaderSettingsChanged ); | ||
155 | setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); | 100 | connect( The::paletteHandler(), &PaletteHandler::newPalette, this, &ContextView::updatePalette ); | ||
156 | // setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); | 101 | | ||
157 | 102 | updateSpacing(); | |||
158 | //make background transparent | 103 | updateDevicePixelRatio( qApp->primaryScreen() ); | ||
159 | QPalette p = palette(); | | |||
160 | QColor c = p.color( QPalette::Base ); | | |||
161 | c.setAlpha( 0 ); | | |||
162 | p.setColor( QPalette::Base, c ); | | |||
163 | setPalette( p ); | | |||
164 | | ||||
165 | contextScene()->setAppletMimeType( "text/x-amarokappletservicename" ); | | |||
166 | | ||||
167 | if (cont) { | | |||
168 | setScene(cont->scene()); | | |||
169 | setContainment(cont); | | |||
170 | } | | |||
171 | | ||||
172 | cont->setPos( 0, 0 ); | | |||
173 | cont->updateConstraints(); | | |||
174 | Containment* amarokContainment = qobject_cast<Containment* >( cont ); | | |||
175 | if( amarokContainment ) | | |||
176 | amarokContainment->setView( this ); | | |||
177 | 104 | | |||
178 | m_urlRunner = new ContextUrlRunner(); | 105 | m_urlRunner = new ContextUrlRunner(); | ||
179 | The::amarokUrlHandler()->registerRunner( m_urlRunner, "context" ); | 106 | The::amarokUrlHandler()->registerRunner( m_urlRunner, "context" ); | ||
180 | 107 | | |||
181 | m_queuedAnimations = new QSequentialAnimationGroup( this ); | 108 | rootContext()->setContextProperty( QStringLiteral( "AppletModel" ), m_appletModel ); | ||
182 | m_collapseAnimations = new QParallelAnimationGroup( this ); | 109 | rootContext()->setContextProperty( QStringLiteral( "AppletProxyModel" ), m_proxyModel ); | ||
183 | connect( m_collapseAnimations, SIGNAL(finished()), | 110 | rootContext()->setContextProperty( QStringLiteral( "Context" ), this ); | ||
184 | this, SLOT(slotCollapseAnimationsFinished()) ); | 111 | rootContext()->setContextProperty( QStringLiteral( "Svg" ), The::svgHandler() ); | ||
185 | | ||||
186 | m_collapseGroupTimer = new QTimer( this ); | | |||
187 | m_collapseGroupTimer->setSingleShot( true ); | | |||
188 | connect( m_collapseGroupTimer, SIGNAL(timeout()), SLOT(slotStartCollapseAnimations()) ); | | |||
189 | | ||||
190 | EngineController* const engine = The::engineController(); | | |||
191 | | ||||
192 | connect( engine, SIGNAL(trackChanged(Meta::TrackPtr)), | | |||
193 | this, SLOT(slotTrackChanged(Meta::TrackPtr)) ); | | |||
194 | connect( engine, SIGNAL(trackMetadataChanged(Meta::TrackPtr)), | | |||
195 | this, SLOT(slotMetadataChanged(Meta::TrackPtr)) ); | | |||
196 | 112 | | |||
197 | // keep this assignment at bottom so that premature usage of ::self() asserts out | 113 | quickWindow()->setColor( The::paletteHandler()->palette().color( QPalette::Window ) ); | ||
198 | s_self = this; | | |||
199 | } | | |||
200 | 114 | | |||
201 | ContextView::~ContextView() | 115 | auto qmlPackage = KPackage::PackageLoader::self()->loadPackage( QStringLiteral( "KPackage/GenericQML" ), | ||
202 | { | 116 | QStringLiteral( "org.kde.amarok.context" ) ); | ||
203 | DEBUG_BLOCK | 117 | Q_ASSERT( qmlPackage.isValid() ); | ||
204 | | ||||
205 | // Unload and destroy all Amarok plasma-engines | | |||
206 | const QStringList engines = Plasma::DataEngineManager::self()->listAllEngines( "Amarok" ); | | |||
207 | 118 | | |||
208 | // Assert added for tracing crash on exit, see BUG 187384 | 119 | const QString sourcePath = qmlPackage.filePath( "mainscript" ); | ||
209 | Q_ASSERT_X( !engines.isEmpty(), "Listing loaded Plasma engines", "List is empty (no engines loaded!?)" ); | 120 | Q_ASSERT( QFile::exists( sourcePath ) ); | ||
210 | 121 | | |||
211 | foreach( const QString &engine, engines ) | 122 | ::debug() << "Loading context qml mainscript:" << sourcePath; | ||
212 | { | | |||
213 | debug() << "Unloading plasma engine: " << engine; | | |||
214 | | ||||
215 | // PlasmaDataEngineManager uses refcounting for the engines, so we need to unload until the refcount reaches 0 | | |||
216 | while( Plasma::DataEngineManager::self()->engine( engine )->isValid() ) | | |||
217 | Plasma::DataEngineManager::self()->unloadEngine( engine ); | | |||
218 | } | | |||
219 | 123 | | |||
220 | clear( m_curState ); | 124 | setSource( QUrl::fromLocalFile( sourcePath ) ); | ||
221 | //this should be done to prevent a crash on exit | 125 | setResizeMode( SizeRootObjectToView ); | ||
222 | clearFocus(); | | |||
223 | 126 | | |||
224 | delete m_urlRunner; | 127 | // keep this assignment at bottom so that premature usage of ::self() asserts out | ||
128 | s_self = this; | ||||
225 | } | 129 | } | ||
226 | 130 | | |||
227 | 131 | ContextView::~ContextView() | |||
228 | void | | |||
229 | ContextView::clear( const ContextState& state ) | | |||
230 | { | 132 | { | ||
231 | Q_UNUSED( state ) | | |||
232 | DEBUG_BLOCK | 133 | DEBUG_BLOCK | ||
233 | 134 | | |||
234 | const QString name = "amarok_homerc"; | 135 | delete m_urlRunner; | ||
235 | // now we save the state, remembering the column info etc | 136 | s_self = Q_NULLPTR; | ||
236 | KConfig appletConfig( name ); | | |||
237 | // erase previous config | | |||
238 | foreach( const QString& group, appletConfig.groupList() ) | | |||
239 | appletConfig.deleteGroup( group ); | | |||
240 | | ||||
241 | const int numContainments = contextScene()->containments().size(); | | |||
242 | for( int i = 0; i < numContainments; i++ ) | | |||
243 | { | | |||
244 | DEBUG_LINE_INFO | | |||
245 | Containment* containment = qobject_cast< Containment* >( contextScene()->containments()[i] ); | | |||
246 | KConfigGroup cg( &appletConfig, QString( "Containment %1" ).arg( i ) ); | | |||
247 | if( containment ) | | |||
248 | containment->saveToConfig( cg ); | | |||
249 | } | | |||
250 | contextScene()->clearContainments(); | | |||
251 | } | | |||
252 | | ||||
253 | void ContextView::clearNoSave() | | |||
254 | { | | |||
255 | contextScene()->clearContainments(); | | |||
256 | } | 137 | } | ||
257 | 138 | | |||
258 | 139 | QStringList | |||
259 | void ContextView::slotTrackChanged( Meta::TrackPtr track ) | 140 | ContextView::currentApplets() const | ||
260 | { | 141 | { | ||
261 | if( track ) | 142 | QStringList appletNames; | ||
262 | messageNotify( Current ); | | |||
263 | else | | |||
264 | messageNotify( Home ); | | |||
265 | } | | |||
266 | | ||||
267 | 143 | | |||
268 | void | 144 | auto applets = m_loader->enabledApplets(); | ||
269 | ContextView::slotMetadataChanged( Meta::TrackPtr track ) | 145 | for( const auto &applet : applets ) | ||
270 | { | 146 | { | ||
271 | DEBUG_BLOCK | 147 | appletNames << applet.pluginId(); | ||
272 | | ||||
273 | // if we are listening to a stream, take the new metadata as a "new track" | | |||
274 | if( track && The::engineController()->isStream() ) | | |||
275 | messageNotify( Current ); | | |||
276 | } | 148 | } | ||
277 | 149 | | |||
278 | void ContextView::showHome() | 150 | ::debug() << "Current applets: " << appletNames; | ||
279 | { | | |||
280 | DEBUG_BLOCK | | |||
281 | 151 | | |||
282 | m_curState = Home; | 152 | return appletNames; | ||
283 | loadConfig(); | | |||
284 | messageNotify( m_curState ); | | |||
285 | } | 153 | } | ||
286 | 154 | | |||
287 | 155 | QStringList | |||
288 | // loads applets onto the ContextScene from saved data, using m_curState | 156 | ContextView::currentAppletNames() const | ||
289 | void | | |||
290 | ContextView::loadConfig() | | |||
291 | { | 157 | { | ||
292 | contextScene()->clearContainments(); | 158 | QStringList appletNames; | ||
293 | 159 | | |||
294 | PERF_LOG( "Start to load config" ); | 160 | auto applets = m_loader->enabledApplets(); | ||
295 | int numContainments = contextScene()->containments().size(); | 161 | for( const auto &applet : applets ) | ||
296 | KConfig conf( "amarok_homerc", KConfig::FullConfig ); | | |||
297 | for( int i = 0; i < numContainments; i++ ) | | |||
298 | { | | |||
299 | Containment* containment = qobject_cast< Containment* >( contextScene()->containments()[i] ); | | |||
300 | if( containment ) | | |||
301 | { | | |||
302 | KConfigGroup cg( &conf, QString( "Containment %1" ).arg( i ) ); | | |||
303 | #ifdef QT_QTOPENGL_FOUND | | |||
304 | // Special case: If this is the first time that the user runs an Amarok version | | |||
305 | // containing the Analyzer applet, modify the user's config so that the applet | | |||
306 | // will become active. We do this for discoverability and prettiness. | | |||
307 | // Remove this code in a future Amarok release (possibly 3.0) | | |||
308 | const bool firstTimeWithAnalyzer = Amarok::config( "Context View" ).readEntry( "firstTimeWithAnalyzer", true ); | | |||
309 | if( firstTimeWithAnalyzer ) | | |||
310 | { | 162 | { | ||
311 | QStringList plugins = cg.readEntry( "plugins", QStringList() ); | 163 | appletNames << applet.name(); | ||
312 | if( EngineController::instance()->supportsAudioDataOutput() && !plugins.contains( "analyzer" ) ) | | |||
313 | { | | |||
314 | Amarok::config( "Context View" ).writeEntry( "firstTimeWithAnalyzer", false ); | | |||
315 | | ||||
316 | // Put the Analyzer applet at position #2, which is most likely below the Currenttrack applet. | | |||
317 | if( !plugins.empty() ) | | |||
318 | plugins.insert( 1, "analyzer" ); | | |||
319 | | ||||
320 | cg.writeEntry( "plugins", plugins ); | | |||
321 | } | | |||
322 | } | | |||
323 | #endif | | |||
324 | containment->loadConfig( cg ); | | |||
325 | } | | |||
326 | } | | |||
327 | PERF_LOG( "Done loading config" ); | | |||
328 | } | 164 | } | ||
329 | 165 | | |||
330 | void | 166 | ::debug() << "Current applet names: " << appletNames; | ||
331 | ContextView::addCollapseAnimation( QAbstractAnimation *anim ) | | |||
332 | { | | |||
333 | if( !anim ) | | |||
334 | { | | |||
335 | debug() << "failed to add collapsing animation"; | | |||
336 | return; | | |||
337 | } | | |||
338 | 167 | | |||
339 | if( m_collapseAnimations->state() == QAbstractAnimation::Running || | 168 | return appletNames; | ||
340 | m_collapseGroupTimer->isActive() ) | | |||
341 | { | | |||
342 | m_queuedAnimations->addAnimation( anim ); | | |||
343 | } | | |||
344 | else | | |||
345 | { | | |||
346 | m_collapseAnimations->addAnimation( anim ); | | |||
347 | m_collapseGroupTimer->start( 0 ); | | |||
348 | } | | |||
349 | } | 169 | } | ||
350 | 170 | | |||
351 | void | 171 | void | ||
352 | ContextView::slotCollapseAnimationsFinished() | 172 | ContextView::runLink( const QUrl& link ) const | ||
353 | { | 173 | { | ||
354 | m_collapseGroupTimer->stop(); | 174 | if( link.scheme() == QStringLiteral( "amarok" ) ) | ||
355 | m_collapseAnimations->clear(); | | |||
356 | | ||||
357 | while( m_queuedAnimations->animationCount() > 0 ) | | |||
358 | { | 175 | { | ||
359 | if( QAbstractAnimation *anim = m_queuedAnimations->takeAnimation(0) ) | 176 | AmarokUrl aUrl( link.toString() ); | ||
360 | m_collapseAnimations->addAnimation( anim ); | 177 | aUrl.run(); | ||
361 | } | 178 | } | ||
362 | 179 | else | |||
363 | if( m_collapseAnimations->animationCount() > 0 ) | 180 | QDesktopServices::openUrl( link ); | ||
364 | m_collapseGroupTimer->start( 0 ); | | |||
365 | } | 181 | } | ||
366 | 182 | | |||
367 | void | 183 | void | ||
368 | ContextView::slotStartCollapseAnimations() | 184 | ContextView::slotStatusChanged( Status status ) | ||
369 | { | 185 | { | ||
370 | if( m_collapseAnimations->animationCount() > 0 ) | 186 | if( status == Error ) | ||
371 | m_collapseAnimations->start( QAbstractAnimation::KeepWhenStopped ); | 187 | for( const auto &e : errors() ) | ||
188 | error( e.description() ); | ||||
372 | } | 189 | } | ||
373 | 190 | | |||
374 | void | 191 | void | ||
375 | ContextView::hideAppletExplorer() | 192 | ContextView::updateSpacing() | ||
376 | { | 193 | { | ||
377 | if( m_appletExplorer ) | 194 | int gridUnit = QFontMetrics( QGuiApplication::font() ).boundingRect( QStringLiteral("M") ).height(); | ||
378 | m_appletExplorer->hide(); | 195 | if (gridUnit % 2 != 0) | ||
379 | } | 196 | gridUnit++; | ||
380 | 197 | | |||
381 | void | 198 | if (gridUnit != m_largeSpacing) | ||
382 | ContextView::showAppletExplorer() | | |||
383 | { | | |||
384 | if( !m_appletExplorer ) | | |||
385 | { | 199 | { | ||
386 | Context::Containment *cont = qobject_cast<Context::Containment*>( containment() ); | 200 | m_smallSpacing = qMax( 2, (int)( gridUnit / 4 ) ); // 1/4 of gridUnit, at least 2 | ||
387 | m_appletExplorer = new AppletExplorer( cont ); | 201 | m_largeSpacing = gridUnit; // msize.height | ||
388 | m_appletExplorer->setContainment( cont ); | 202 | emit spacingChanged(); | ||
389 | m_appletExplorer->setZValue( m_appletExplorer->zValue() + 1000 ); | | |||
390 | m_appletExplorer->setFlag( QGraphicsItem::ItemIsSelectable ); | | |||
391 | | ||||
392 | connect( m_appletExplorer, SIGNAL(addAppletToContainment(QString,int)), | | |||
393 | cont, SLOT(addApplet(QString,int)) ); | | |||
394 | connect( m_appletExplorer, SIGNAL(appletExplorerHid()), SIGNAL(appletExplorerHid()) ); | | |||
395 | connect( m_appletExplorer, SIGNAL(geometryChanged()), SLOT(slotPositionAppletExplorer()) ); | | |||
396 | | ||||
397 | qreal height = m_appletExplorer->effectiveSizeHint( Qt::PreferredSize ).height(); | | |||
398 | m_appletExplorer->resize( rect().width() - 2, height ); | | |||
399 | m_appletExplorer->setPos( 0, rect().height() - height - 2 ); | | |||
400 | } | 203 | } | ||
401 | m_appletExplorer->show(); | | |||
402 | } | 204 | } | ||
403 | 205 | | |||
404 | void | 206 | void | ||
405 | ContextView::slotPositionAppletExplorer() | 207 | ContextView::updateDevicePixelRatio( QScreen *screen ) | ||
406 | { | 208 | { | ||
407 | if( !m_appletExplorer ) | 209 | if (!screen) | ||
408 | return; | 210 | return; | ||
409 | qreal height = m_appletExplorer->effectiveSizeHint( Qt::PreferredSize ).height(); | | |||
410 | m_appletExplorer->setPos( 0, rect().height() - height - 2 ); | | |||
411 | } | | |||
412 | | ||||
413 | 211 | | |||
414 | ContextScene* | 212 | const qreal dpi = screen->logicalDotsPerInchX(); | ||
415 | ContextView::contextScene() | 213 | // Usual "default" is 96 dpi | ||
416 | { | 214 | m_devicePixelRatio = (qreal)dpi / (qreal)96; | ||
417 | return static_cast<ContextScene*>( scene() ); | 215 | iconLoaderSettingsChanged(); | ||
216 | emit devicePixelRatioChanged(); | ||||
418 | } | 217 | } | ||
419 | 218 | | |||
420 | void | 219 | void | ||
421 | ContextView::resizeEvent( QResizeEvent* event ) | 220 | ContextView::iconLoaderSettingsChanged() | ||
422 | { | 221 | { | ||
423 | QGraphicsView::resizeEvent( event ); | 222 | m_iconSizes->insert( QStringLiteral( "tiny" ), devicePixelIconSize( KIconLoader::SizeSmall ) / 2 ); | ||
424 | if( testAttribute( Qt::WA_PendingResizeEvent ) ) | 223 | m_iconSizes->insert( QStringLiteral( "small" ), devicePixelIconSize( KIconLoader::SizeSmall ) ); | ||
425 | return; // lets not do this more than necessary, shall we? | 224 | m_iconSizes->insert( QStringLiteral( "smallMedium" ), devicePixelIconSize( KIconLoader::SizeSmallMedium ) ); | ||
426 | 225 | m_iconSizes->insert( QStringLiteral( "medium" ), devicePixelIconSize( KIconLoader::SizeMedium ) ); | |||
427 | QRectF rect( pos(), maximumViewportSize() ); | 226 | m_iconSizes->insert( QStringLiteral( "large" ), devicePixelIconSize( KIconLoader::SizeLarge ) ); | ||
428 | containment()->setGeometry( rect ); | 227 | m_iconSizes->insert( QStringLiteral( "huge" ), devicePixelIconSize( KIconLoader::SizeHuge ) ); | ||
429 | scene()->setSceneRect( rect ); | 228 | m_iconSizes->insert( QStringLiteral( "enormous" ), devicePixelIconSize( KIconLoader::SizeEnormous ) ); | ||
430 | scene()->update( rect ); | 229 | | ||
431 | 230 | emit iconSizesChanged(); | |||
432 | if( m_appletExplorer ) | 231 | } | ||
433 | { | 232 | | ||
434 | qreal height = m_appletExplorer->effectiveSizeHint( Qt::PreferredSize ).height(); | 233 | int | ||
435 | m_appletExplorer->resize( rect.width() - 2, height ); | 234 | ContextView::devicePixelIconSize( int size ) const | ||
436 | m_appletExplorer->setPos( 0, rect.height() - height - 2 ); | 235 | { | ||
437 | } | 236 | const qreal ratio = devicePixelRatio(); | ||
237 | | ||||
238 | if ( ratio < 1.5 ) | ||||
239 | return size; | ||||
240 | else if ( ratio < 2.0 ) | ||||
241 | return size * 1.5; | ||||
242 | else if ( ratio < 2.5 ) | ||||
243 | return size * 2.0; | ||||
244 | else if ( ratio < 3.0 ) | ||||
245 | return size * 2.5; | ||||
246 | else if ( ratio < 3.5 ) | ||||
247 | return size * 3.0; | ||||
248 | else | ||||
249 | return size * ratio; | ||||
438 | } | 250 | } | ||
439 | 251 | | |||
440 | void | 252 | void | ||
441 | ContextView::wheelEvent( QWheelEvent* event ) | 253 | ContextView::updatePalette( const QPalette &palette ) | ||
442 | { | | |||
443 | if( event->orientation() != Qt::Horizontal ) | | |||
444 | QGraphicsView::wheelEvent( event ); | | |||
445 | } | | |||
446 | | ||||
447 | QStringList | | |||
448 | ContextView::currentApplets() | | |||
449 | { | | |||
450 | DEBUG_BLOCK | | |||
451 | QStringList appletNames; | | |||
452 | | ||||
453 | Applet::List applets = containment()->applets(); | | |||
454 | foreach( Plasma::Applet * applet, applets ) | | |||
455 | { | 254 | { | ||
456 | appletNames << applet->pluginName(); | 255 | quickWindow()->setColor( palette.color( QPalette::Window ) ); | ||
457 | } | 256 | } | ||
458 | 257 | | |||
459 | debug() << "current applets: " << appletNames; | 258 | void | ||
460 | 259 | ContextView::debug( const QString &error ) const | |||
461 | return appletNames; | | |||
462 | } | | |||
463 | | ||||
464 | QStringList ContextView::currentAppletNames() | | |||
465 | { | | |||
466 | DEBUG_BLOCK | | |||
467 | QStringList appletNames; | | |||
468 | | ||||
469 | Applet::List applets = containment()->applets(); | | |||
470 | foreach( Plasma::Applet * applet, applets ) | | |||
471 | { | 260 | { | ||
472 | appletNames << applet->name(); | 261 | ::debug() << error; | ||
473 | } | 262 | } | ||
474 | 263 | | |||
475 | debug() << "current applets: " << appletNames; | 264 | void | ||
476 | 265 | ContextView::warning( const QString &error ) const | |||
477 | return appletNames; | | |||
478 | } | | |||
479 | | ||||
480 | Containment *ContextView::containment() const | | |||
481 | { | 266 | { | ||
482 | return d->containment; | 267 | ::warning() << error; | ||
483 | } | 268 | } | ||
484 | 269 | | |||
485 | void ContextView::setContainment(Plasma::Containment *containment) | 270 | void | ||
271 | ContextView::error( const QString &error ) const | ||||
486 | { | 272 | { | ||
487 | if (containment == d->containment) { | 273 | ::error() << error; | ||
488 | return; | | |||
489 | } | | |||
490 | | ||||
491 | if (d->containment) { | | |||
492 | disconnect(d->containment, SIGNAL(destroyed(QObject*)), this, SLOT(containmentDestroyed())); | | |||
493 | disconnect(d->containment, SIGNAL(geometryChanged()), this, SLOT(updateSceneRect())); | | |||
494 | disconnect(d->containment, SIGNAL(screenChanged(int, int, Plasma::Containment *)), this, SLOT(containmentScreenChanged(int, int, Plasma::Containment *))); | | |||
495 | d->containment->removeAssociatedWidget(this); | | |||
496 | } | | |||
497 | | ||||
498 | if (!containment) { | | |||
499 | d->containment = 0; | | |||
500 | return; | | |||
501 | } | | |||
502 | | ||||
503 | Containment *oldContainment = d->containment; | | |||
504 | | ||||
505 | int screen = -1; | | |||
506 | int desktop = -1; | | |||
507 | if (oldContainment) { | | |||
508 | screen = d->containment->screen(); | | |||
509 | desktop = d->containment->desktop(); | | |||
510 | } else { | | |||
511 | setScene(containment->scene()); | | |||
512 | } | | |||
513 | | ||||
514 | d->containment = containment; | | |||
515 | | ||||
516 | //add keyboard-shortcut actions | | |||
517 | d->containment->addAssociatedWidget(this); | | |||
518 | | ||||
519 | int otherScreen = containment->screen(); | | |||
520 | int otherDesktop = containment->desktop(); | | |||
521 | | ||||
522 | if (screen > -1) { | | |||
523 | d->lastScreen = screen; | | |||
524 | d->lastDesktop = desktop; | | |||
525 | containment->setScreen(screen, desktop); | | |||
526 | } else { | | |||
527 | d->lastScreen = otherScreen; | | |||
528 | d->lastDesktop = otherDesktop; | | |||
529 | } | | |||
530 | | ||||
531 | if (oldContainment && otherScreen > -1) { | | |||
532 | // assign the old containment the old screen/desktop | | |||
533 | oldContainment->setScreen(otherScreen, otherDesktop); | | |||
534 | } | | |||
535 | | ||||
536 | d->updateSceneRect(); | | |||
537 | connect(containment, SIGNAL(destroyed(QObject*)), this, SLOT(containmentDestroyed())); | | |||
538 | connect(containment, SIGNAL(geometryChanged()), this, SLOT(updateSceneRect())); | | |||
539 | connect(containment, SIGNAL(screenChanged(int, int, Plasma::Containment *)), this, SLOT(containmentScreenChanged(int, int, Plasma::Containment *))); | | |||
540 | } | 274 | } | ||
541 | 275 | | |||
542 | } // Context namespace | 276 | } // Context namespace | ||
543 | 277 | | |||
278 | #include <ContextView.moc> |