1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "AnnotationTableObject.h"
23
24 #include <QCoreApplication>
25
26 #include <U2Core/AnnotationModification.h>
27 #include <U2Core/AnnotationTableObjectConstraints.h>
28 #include <U2Core/DocumentModel.h>
29 #include <U2Core/GHints.h>
30 #include <U2Core/L10n.h>
31 #include <U2Core/Timer.h>
32 #include <U2Core/U2DbiUtils.h>
33 #include <U2Core/U2FeatureUtils.h>
34 #include <U2Core/U2ObjectDbi.h>
35 #include <U2Core/U2OpStatusUtils.h>
36 #include <U2Core/U2SafePoints.h>
37
38 #include "GObjectTypes.h"
39
40 namespace U2 {
41
AnnotationTableObject(const QString & objectName,const U2DbiRef & dbiRef,const QVariantMap & hintsMap)42 AnnotationTableObject::AnnotationTableObject(const QString &objectName, const U2DbiRef &dbiRef, const QVariantMap &hintsMap)
43 : GObject(GObjectTypes::ANNOTATION_TABLE, objectName, hintsMap) {
44 U2OpStatusImpl os;
45 const QString folder = hintsMap.value(DocumentFormat::DBI_FOLDER_HINT, U2ObjectDbi::ROOT_FOLDER).toString();
46 U2AnnotationTable table = U2FeatureUtils::createAnnotationTable(objectName, dbiRef, folder, os);
47 SAFE_POINT_OP(os, );
48
49 entityRef = U2EntityRef(dbiRef, table.id);
50 rootGroup = new AnnotationGroup(table.rootFeature, AnnotationGroup::ROOT_GROUP_NAME, nullptr, this);
51 dataLoaded = true;
52 }
53
AnnotationTableObject(const QString & objectName,const U2EntityRef & tableRef,const QVariantMap & hintsMap)54 AnnotationTableObject::AnnotationTableObject(const QString &objectName, const U2EntityRef &tableRef, const QVariantMap &hintsMap)
55 : GObject(GObjectTypes::ANNOTATION_TABLE, objectName, hintsMap), rootGroup(nullptr) {
56 entityRef = tableRef;
57 }
58
~AnnotationTableObject()59 AnnotationTableObject::~AnnotationTableObject() {
60 delete rootGroup;
61 }
62
getAnnotations() const63 QList<Annotation *> AnnotationTableObject::getAnnotations() const {
64 ensureDataLoaded();
65 return rootGroup->getAnnotations(true);
66 }
67
hasAnnotations() const68 bool AnnotationTableObject::hasAnnotations() const {
69 ensureDataLoaded();
70 return rootGroup->hasAnnotations();
71 }
72
getRootGroup()73 AnnotationGroup *AnnotationTableObject::getRootGroup() {
74 ensureDataLoaded();
75 return rootGroup;
76 }
77
78 typedef QPair<AnnotationGroup *, QList<SharedAnnotationData>> AnnotationGroupData;
79
addAnnotations(const QList<SharedAnnotationData> & annotations,const QString & groupName)80 QList<Annotation *> AnnotationTableObject::addAnnotations(const QList<SharedAnnotationData> &annotations, const QString &groupName) {
81 QList<Annotation *> result;
82 CHECK(!annotations.isEmpty(), result);
83
84 ensureDataLoaded();
85
86 if (groupName.isEmpty()) {
87 QMap<QString, AnnotationGroupData> group2Annotations;
88 for (const SharedAnnotationData &a : qAsConst(annotations)) {
89 if (!group2Annotations.contains(a->name)) {
90 AnnotationGroup *group = rootGroup->getSubgroup(a->name, true);
91 group2Annotations[a->name].first = group;
92 }
93 group2Annotations[a->name].second.append(a);
94 }
95 for (const AnnotationGroupData &groupData : qAsConst(group2Annotations)) {
96 result.append(groupData.first->addAnnotations(groupData.second));
97 }
98 } else {
99 AnnotationGroup *group = rootGroup->getSubgroup(groupName, true);
100 result.append(group->addAnnotations(annotations));
101 }
102 return result;
103 }
104
removeAnnotations(const QList<Annotation * > & annotations)105 void AnnotationTableObject::removeAnnotations(const QList<Annotation *> &annotations) {
106 CHECK(!annotations.isEmpty(), );
107
108 QMap<AnnotationGroup *, QList<Annotation *>> group2Annotations;
109 foreach (Annotation *ann, annotations) {
110 SAFE_POINT(ann->getGObject() == this, "Unexpected annotation detected", );
111 group2Annotations[ann->getGroup()].append(ann);
112 }
113
114 foreach (AnnotationGroup *group, group2Annotations.keys()) {
115 group->removeAnnotations(group2Annotations[group]);
116 }
117 }
118
clone(const U2DbiRef & ref,U2OpStatus & os,const QVariantMap & hints) const119 GObject *AnnotationTableObject::clone(const U2DbiRef &ref, U2OpStatus &os, const QVariantMap &hints) const {
120 ensureDataLoaded();
121
122 GHintsDefaultImpl gHints(getGHintsMap());
123 gHints.setAll(hints);
124
125 DbiOperationsBlock opBlock(ref, os);
126 CHECK_OP(os, nullptr);
127
128 AnnotationTableObject *cln = new AnnotationTableObject(getGObjectName(), ref, gHints.getMap());
129 cln->setIndexInfo(getIndexInfo());
130
131 QStringList subgroupPaths;
132 rootGroup->getSubgroupPaths(subgroupPaths);
133 AnnotationGroup *clonedRootGroup = cln->getRootGroup();
134 for (const QString &groupPath : qAsConst(subgroupPaths)) {
135 AnnotationGroup *originalGroup = rootGroup->getSubgroup(groupPath, false);
136 SAFE_POINT(originalGroup != nullptr, L10N::nullPointerError("annotation group"), nullptr);
137
138 AnnotationGroup *clonedGroup = clonedRootGroup->getSubgroup(groupPath, true);
139 QList<SharedAnnotationData> groupData;
140 foreach (const Annotation *a, originalGroup->getAnnotations()) {
141 groupData.append(a->getData());
142 }
143 clonedGroup->addAnnotations(groupData);
144 }
145
146 return cln;
147 }
148
getAnnotationsByName(const QString & name) const149 QList<Annotation *> AnnotationTableObject::getAnnotationsByName(const QString &name) const {
150 QList<Annotation *> result;
151
152 ensureDataLoaded();
153
154 foreach (Annotation *a, getAnnotations()) {
155 if (a->getName() == name) {
156 result.append(a);
157 }
158 }
159
160 return result;
161 }
162
163 namespace {
164
annotationIntersectsRange(const Annotation * a,const U2Region & range,bool contains)165 bool annotationIntersectsRange(const Annotation *a, const U2Region &range, bool contains) {
166 SAFE_POINT(nullptr != a, L10N::nullPointerError("annotation"), false);
167 if (!contains) {
168 foreach (const U2Region &r, a->getRegions()) {
169 if (r.intersects(range)) {
170 return true;
171 }
172 }
173 return false;
174 } else {
175 foreach (const U2Region &r, a->getRegions()) {
176 if (!range.contains(r)) {
177 return false;
178 }
179 }
180 return true;
181 }
182 }
183
184 } // namespace
185
getAnnotationsByRegion(const U2Region & region,bool contains) const186 QList<Annotation *> AnnotationTableObject::getAnnotationsByRegion(const U2Region ®ion, bool contains) const {
187 QList<Annotation *> result;
188
189 ensureDataLoaded();
190
191 foreach (Annotation *a, getAnnotations()) {
192 if (annotationIntersectsRange(a, region, contains)) {
193 result.append(a);
194 }
195 }
196
197 return result;
198 }
199
getAnnotationsByType(const U2FeatureType featureType) const200 QList<Annotation *> AnnotationTableObject::getAnnotationsByType(const U2FeatureType featureType) const {
201 QList<Annotation *> result;
202
203 ensureDataLoaded();
204
205 foreach (Annotation *a, getAnnotations()) {
206 if (a->getType() == featureType) {
207 result.append(a);
208 }
209 }
210
211 return result;
212 }
213
checkConstraints(const GObjectConstraints * c) const214 bool AnnotationTableObject::checkConstraints(const GObjectConstraints *c) const {
215 auto ac = qobject_cast<const AnnotationTableObjectConstraints *>(c);
216 SAFE_POINT(ac != nullptr, "Invalid feature constraints", false);
217
218 ensureDataLoaded();
219
220 int fitSize = ac->sequenceSizeToFit;
221 SAFE_POINT(fitSize > 0, "Invalid sequence length provided!", false);
222 QList<Annotation *> annotations = getAnnotations();
223 for (const Annotation *a : qAsConst(annotations)) {
224 const QVector<U2Region> ®ions = a->getRegions();
225 for (const U2Region ®ion : qAsConst(regions)) {
226 SAFE_POINT(region.startPos >= 0, "Invalid annotation region", false);
227 if (region.endPos() > fitSize) {
228 return false;
229 }
230 }
231 }
232 return true;
233 }
234
setGObjectName(const QString & newName)235 void AnnotationTableObject::setGObjectName(const QString &newName) {
236 CHECK(name != newName, );
237
238 ensureDataLoaded();
239 GObject::setGObjectName(newName);
240 }
241
getRootFeatureId() const242 U2DataId AnnotationTableObject::getRootFeatureId() const {
243 ensureDataLoaded();
244
245 return rootGroup->id;
246 }
247
emit_onAnnotationsAdded(const QList<Annotation * > & l)248 void AnnotationTableObject::emit_onAnnotationsAdded(const QList<Annotation *> &l) {
249 emit si_onAnnotationsAdded(l);
250 }
251
emit_onAnnotationsModified(const AnnotationModification & annotationModification)252 void AnnotationTableObject::emit_onAnnotationsModified(const AnnotationModification &annotationModification) {
253 emit_onAnnotationsModified(QList<AnnotationModification>() << annotationModification);
254 }
255
emit_onAnnotationsModified(const QList<AnnotationModification> & annotationModifications)256 void AnnotationTableObject::emit_onAnnotationsModified(const QList<AnnotationModification> &annotationModifications) {
257 emit si_onAnnotationsModified(annotationModifications);
258 }
259
emit_onAnnotationsRemoved(const QList<Annotation * > & a)260 void AnnotationTableObject::emit_onAnnotationsRemoved(const QList<Annotation *> &a) {
261 emit si_onAnnotationsRemoved(a);
262 }
263
emit_onGroupCreated(AnnotationGroup * g)264 void AnnotationTableObject::emit_onGroupCreated(AnnotationGroup *g) {
265 emit si_onGroupCreated(g);
266 }
267
emit_onGroupRemoved(AnnotationGroup * p,AnnotationGroup * g)268 void AnnotationTableObject::emit_onGroupRemoved(AnnotationGroup *p, AnnotationGroup *g) {
269 emit si_onGroupRemoved(p, g);
270 }
271
emit_onGroupRenamed(AnnotationGroup * g)272 void AnnotationTableObject::emit_onGroupRenamed(AnnotationGroup *g) {
273 emit si_onGroupRenamed(g);
274 }
275
emit_onAnnotationsInGroupRemoved(const QList<Annotation * > & l,AnnotationGroup * gr)276 void AnnotationTableObject::emit_onAnnotationsInGroupRemoved(const QList<Annotation *> &l, AnnotationGroup *gr) {
277 emit si_onAnnotationsInGroupRemoved(l, gr);
278 }
279
loadDataCore(U2OpStatus & os)280 void AnnotationTableObject::loadDataCore(U2OpStatus &os) {
281 SAFE_POINT(nullptr == rootGroup, "Annotation table is initialized unexpectedly", );
282
283 U2AnnotationTable table = U2FeatureUtils::getAnnotationTable(entityRef, os);
284 CHECK_OP(os, );
285
286 rootGroup = U2FeatureUtils::loadAnnotationTable(table.rootFeature, entityRef.dbiRef, this, os);
287 }
288
289 } // namespace U2
290