1 /*
2  * %injeqt copyright begin%
3  * Copyright 2014 Rafał Malinowski (rafal.przemyslaw.malinowski@gmail.com)
4  * %injeqt copyright end%
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #pragma once
22 
23 #include <injeqt/exception/exception.h>
24 #include <injeqt/injeqt.h>
25 #include <injeqt/type.h>
26 
27 #include "internal.h"
28 #include "types-by-name.h"
29 
30 #include <QtCore/QMetaMethod>
31 
32 /**
33  * @file
34  * @brief Contains classes and functions for representing setter methods.
35  */
36 
37 namespace injeqt { namespace internal {
38 
39 /**
40  * @brief Abstraction of setter method.
41  *
42  * This class is used for defining setter based dependencies and for invoking these setter methods
43  * to resolve dependencies. Setter method is crated from Qt type QMetaMethod. As Qt only creates QMetaMethod
44  * objects for slots, signals and all methods marked with Q_INVOKABLE tag and Injeqt requires
45  * all its setter methods to be tagged with INJEQT_SET - setter method must be a slot. This method should return
46  * void is allowed to have only one parameter of pointer to type inherited from QObject. This type must
47  * be also configured in one of module to be able to be resolved.
48  *
49  * Example of valid setter method:
50  *
51  *     class set_object : public QObject
52  *     {
53  *         Q_OBJECT
54  *     };
55  *
56  *     class with_setter : public QObject
57  *     {
58  *         Q_OBJECT
59  *     public slots:
60  *         INJEQT_SET void setter(set_object *obj) { ... }
61  *     };
62  *
63  * Object with setter method must not take ownership of passed object.
64  */
65 class INJEQT_INTERNAL_API setter_method final
66 {
67 
68 public:
69 	static bool is_setter_tag(const std::string &tag);
70 
71 	static bool validate_setter_method(type parameter_type, const QMetaMethod &meta_method);
72 
73 	/**
74 	 * @brief Create empty setter_method.
75 	 */
76 	setter_method();
77 
78 	/**
79 	 * @brief Create object from QMetaMethod definition.
80 	 * @param parameter_type Type of parameter of setter @p meta_method
81 	 * @param meta_method Qt meta method that should be a setter method
82 	 * @note Qt QMetaType system limitations with plugins disallow use of QMetaType to retreive parameter type from QMetaMethod.
83 	 * @pre meta_method.methodType() == QMetaMethod::Slot
84 	 * @pre meta_method.parameterCount() == 1
85 	 * @pre meta_method.enclosingMetaObject() != nullptr
86 	 * @pre !parameter_type.is_empty()
87 	 * @pre parameter_type.name() + "*" == std::string{meta_method.parameterTypes()[0].data()}
88 	 */
89 	explicit setter_method(type parameter_type, QMetaMethod meta_method);
90 
91 	/**
92 	 * @return true if setter_method is empty and does not represent valie setter method
93 	 */
94 	bool is_empty() const;
95 
96 	/**
97 	 * @return Type of objects that owns this setter method.
98 	 *
99 	 * May return invalid type if QMetaMethod passed in constructor was invalid.
100 	 */
101 	const type & object_type() const;
102 
103 	/**
104 	 * @return Type of objects parameter accepted by setter method.
105 	 *
106 	 * May return invalid type if QMetaMethod passed in constructor was invalid.
107 	 */
108 	const type & parameter_type() const;
109 
110 	/**
111 	 * @return Qt representation of setter method.
112 	 *
113 	 * May return empty value if QMetaMethod passed in constructor was invalid.
114 	 */
115 	const QMetaMethod & meta_method() const;
116 
117 	/**
118 	 * @return String signature of setter method.
119 	 *
120 	 * May return empty value if QMetaMethod passed in constructor was invalid.
121 	 */
122 	std::string signature() const;
123 
124 	/**
125 	 * @param on object to call this method on
126 	 * @param parameter parmeter to be passed in invocation
127 	 * @return true if invoke was successfull
128 	 * @pre !is_empty()
129 	 * @pre on != nullptr
130 	 * @pre type{on->metaObject()} == object_type()
131 	 * @pre parameter != nullptr
132 	 * @pre !type{parameter->metaObject()}.is_empty()
133 	 * @pre implements(type{parameter->metaObject()}, _parameter_type)
134 	 *
135 	 * This method can be only called on valid objects with @p on parameter being
136 	 * the same type as object_type() returns and @p parameter of type that implements parameter_type().
137 	 *
138 	 * Calling this on invalid object with result in undefined behavior.
139 	 */
140 	bool invoke(QObject *on, QObject *parameter) const;
141 
142 private:
143 	type _object_type;
144 	type _parameter_type;
145 	QMetaMethod _meta_method;
146 
147 };
148 
149 INJEQT_INTERNAL_API bool operator == (const setter_method &x, const setter_method &y);
150 INJEQT_INTERNAL_API bool operator != (const setter_method &x, const setter_method &y);
151 INJEQT_INTERNAL_API bool operator < (const setter_method &x, const setter_method &y);
152 INJEQT_INTERNAL_API bool operator > (const setter_method &x, const setter_method &y);
153 INJEQT_INTERNAL_API bool operator <= (const setter_method &x, const setter_method &y);
154 INJEQT_INTERNAL_API bool operator >= (const setter_method &x, const setter_method &y);
155 
156 INJEQT_INTERNAL_API setter_method make_setter_method(const types_by_name &known_types, const QMetaMethod &meta_method);
157 
158 }}
159