1 /*
2  * fileformat.h
3  * Copyright 2008-2015, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
4  *
5  * This file is part of libtiled.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  *    1. Redistributions of source code must retain the above copyright notice,
11  *       this list of conditions and the following disclaimer.
12  *
13  *    2. Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in the
15  *       documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20  * EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #pragma once
30 
31 #include "pluginmanager.h"
32 
33 #include <QObject>
34 
35 
36 namespace Tiled {
37 
38 
39 class TILEDSHARED_EXPORT FileFormat : public QObject
40 {
41     Q_OBJECT
42 
43 public:
44     enum Capability {
45         NoCapability    = 0x0,
46         Read            = 0x1,
47         Write           = 0x2,
48         ReadWrite       = Read | Write
49     };
50     Q_DECLARE_FLAGS(Capabilities, Capability)
51 
52     enum Option {
53         WriteMinimized  = 0x1,
54     };
55     Q_DECLARE_FLAGS(Options, Option)
56 
57     explicit FileFormat(QObject *parent = nullptr);
58 
59     /**
60      * Returns whether this format has Read and/or Write capabilities.
61      */
62     virtual Capabilities capabilities() const;
63 
64     /**
65      * Returns whether this format has all given capabilities.
66      */
67     bool hasCapabilities(Capabilities caps) const;
68 
69     /**
70      * Returns name filter for files in this map format.
71      */
72     virtual QString nameFilter() const = 0;
73 
74     /**
75      * Returns short name for this map format
76      */
77     virtual QString shortName() const = 0;
78 
79     /**
80      * Returns whether this map format supports reading the given file.
81      *
82      * Generally would do a file extension check.
83      */
84     virtual bool supportsFile(const QString &fileName) const = 0;
85 
86     /**
87      * Returns the error to be shown to the user if an error occurred while
88      * trying to read or write a file.
89      */
90     virtual QString errorString() const = 0;
91 };
92 
93 } // namespace Tiled
94 
95 Q_DECLARE_INTERFACE(Tiled::FileFormat, "org.mapeditor.FileFormat")
Q_DECLARE_OPERATORS_FOR_FLAGS(Tiled::FileFormat::Capabilities)96 Q_DECLARE_OPERATORS_FOR_FLAGS(Tiled::FileFormat::Capabilities)
97 Q_DECLARE_OPERATORS_FOR_FLAGS(Tiled::FileFormat::Options)
98 
99 namespace Tiled {
100 
101 /**
102  * Convenience class that can be used when implementing file dialogs.
103  */
104 template<typename Format>
105 class FormatHelper
106 {
107 public:
108     FormatHelper(FileFormat::Capabilities capabilities,
109                  QString initialFilter = QString())
110         : mFilter(std::move(initialFilter))
111     {
112         PluginManager::each<Format>([this,capabilities](Format *format) {
113             if (format->hasCapabilities(capabilities)) {
114                 const QString nameFilter = format->nameFilter();
115 
116                 if (!mFilter.isEmpty())
117                     mFilter += QStringLiteral(";;");
118                 mFilter += nameFilter;
119 
120                 mFormats.append(format);
121                 mFormatByNameFilter.insert(nameFilter, format);
122             }
123         });
124     }
125 
126     const QString &filter() const
127     { return mFilter; }
128 
129     const QList<Format*> &formats() const
130     { return mFormats; }
131 
132     Format *findFormat(const QString &shortName) const
133     {
134         auto it = std::find_if(mFormats.begin(),
135                                mFormats.end(),
136                                [&] (Format *format) { return format->shortName() == shortName; });
137         return it != mFormats.end() ? *it : nullptr;
138     }
139 
140     Format *formatByNameFilter(const QString &nameFilter) const
141     { return mFormatByNameFilter.value(nameFilter); }
142 
143 private:
144     QString mFilter;
145     QList<Format*> mFormats;
146     QMap<QString, Format*> mFormatByNameFilter;
147 };
148 
149 template<typename Format>
150 Format *findFileFormat(const QString &shortName, FileFormat::Capabilities capabilities = FileFormat::Write)
151 {
152     if (shortName.isEmpty())
153         return nullptr;
154 
155     return PluginManager::find<Format>([&](Format *format) {
156         return format->hasCapabilities(capabilities) && format->shortName() == shortName;
157     });
158 }
159 
160 } // namespace Tiled
161