1 /** @file fontmanifest.cpp Font resource manifest.
2  *
3  * @authors Copyright © 2003-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4  * @authors Copyright © 2005-2013 Daniel Swanson <danij@dengine.net>
5  *
6  * @par License
7  * GPL: http://www.gnu.org/licenses/gpl.html
8  *
9  * <small>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 the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version. This program is distributed in the hope that it
13  * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15  * Public License for more details. You should have received a copy of the GNU
16  * General Public License along with this program; if not, write to the Free
17  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA</small>
19  */
20 
21 #include "de_platform.h"
22 #include "resource/fontmanifest.h"
23 
24 #include "dd_main.h" // App_Fonts(), remove me
25 #include "FontScheme"
26 #include <de/Log>
27 
28 using namespace de;
29 
DENG2_PIMPL(FontManifest)30 DENG2_PIMPL(FontManifest),
31 DENG2_OBSERVES(AbstractFont, Deletion)
32 {
33     int uniqueId;
34     QScopedPointer<AbstractFont>(resource); ///< Associated resource (if any).
35 
36     Impl(Public *i)
37         : Base(i)
38         , uniqueId(0)
39     {}
40 
41     ~Impl()
42     {
43         DENG2_FOR_PUBLIC_AUDIENCE(Deletion, i) i->fontManifestBeingDeleted(self());
44     }
45 
46     // Observes AbstractFont::Deletion.
47     void fontBeingDeleted(AbstractFont const & /*resource*/)
48     {
49         resource.reset();
50     }
51 };
52 
FontManifest(PathTree::NodeArgs const & args)53 FontManifest::FontManifest(PathTree::NodeArgs const &args)
54     : Node(args), d(new Impl(this))
55 {}
56 
scheme() const57 FontScheme &FontManifest::scheme() const
58 {
59     LOG_AS("FontManifest");
60     /// @todo Optimize: FontManifest should contain a link to the owning FontScheme.
61     foreach(FontScheme *scheme, App_Resources().allFontSchemes())
62     {
63         if(&scheme->index() == &tree()) return *scheme;
64     }
65     /// @throw Error Failed to determine the scheme of the manifest (should never happen...).
66     throw Error("FontManifest::scheme", String("Failed to determine scheme for manifest [%1]").arg(de::dintptr(this)));
67 }
68 
schemeName() const69 String const &FontManifest::schemeName() const
70 {
71     return scheme().name();
72 }
73 
description(de::Uri::ComposeAsTextFlags uriCompositionFlags) const74 String FontManifest::description(de::Uri::ComposeAsTextFlags uriCompositionFlags) const
75 {
76     return String("%1").arg(composeUri().compose(uriCompositionFlags | Uri::DecodePath),
77                             ( uriCompositionFlags.testFlag(Uri::OmitScheme)? -14 : -22 ) );
78 }
79 
uniqueId() const80 int FontManifest::uniqueId() const
81 {
82     return d->uniqueId;
83 }
84 
setUniqueId(int newUniqueId)85 bool FontManifest::setUniqueId(int newUniqueId)
86 {
87     LOG_AS("FontManifest");
88 
89     if(d->uniqueId == newUniqueId) return false;
90 
91     d->uniqueId = newUniqueId;
92 
93     // Notify interested parties that the uniqueId has changed.
94     DENG2_FOR_AUDIENCE(UniqueIdChange, i) i->fontManifestUniqueIdChanged(*this);
95 
96     return true;
97 }
98 
hasResource() const99 bool FontManifest::hasResource() const
100 {
101     return !d->resource.isNull();
102 }
103 
resource() const104 AbstractFont &FontManifest::resource() const
105 {
106     if(hasResource())
107     {
108         return *d->resource.data();
109     }
110     /// @throw MissingFontError No resource is associated with the manifest.
111     throw MissingFontError("FontManifest::resource", "No resource is associated");
112 }
113 
setResource(AbstractFont * newResource)114 void FontManifest::setResource(AbstractFont *newResource)
115 {
116     LOG_AS("FontManifest");
117 
118     if(d->resource.data() != newResource)
119     {
120         if(AbstractFont *curFont = d->resource.data())
121         {
122             // Cancel notifications about the existing resource.
123             curFont->audienceForDeletion -= d;
124         }
125 
126         d->resource.reset(newResource);
127 
128         if(AbstractFont *curFont = d->resource.data())
129         {
130             // We want notification when the new resource is about to be deleted.
131             curFont->audienceForDeletion += d;
132         }
133     }
134 }
135