summaryrefslogtreecommitdiff
path: root/src/imports/location/declarativeplaces/qdeclarativerecommendationmodel.cpp
blob: 9289bbbef9d94e508d464bf2bfbce94733352c48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#include "qdeclarativerecommendationmodel_p.h"

QTM_USE_NAMESPACE

/*!
    \qmlclass RecommenadationModel QDeclarativeRecommenadationModel
    \brief The RecommenadationModel element provides access to recommendation.
    \inherits QAbstractListModel
    \ingroup qml-places

    RecommenadationModel provides a model of recommendation results from PlaceManager.
    The contents of the model is SearchResult list. User can add additional parameters
    which make search more satisfactory. At least position of search center
    should be set. Other parameters are start and limit of returned items, and bounding box
    for the items returned. Also user might set \l dym property if "did you mean"
    items should be returned.

    There are two ways of accessing the data: through model by using views and delegates,
    or alternatively via \l results list property. Of the two, the model access is preferred.

    At the moment only data role provided by the model is \c searchResult.

    Model might be use for different kind of requests. It mighe be used for search request
    with search term where user gives string with query. It might be used for category search.
    User might also use it for recomendation search (search similar places in requested area).
    In that case user pass place id as an input parameter.

    To use RecommenadationModel user need to create it in qml file and connect it to some view
    \code
    import places 1.0

    RecommenadationModel {
        id: searchModel
        searchCenter:
                GeoCoordinates {
                    latitude: 53
                    longitude: 10
                }
        start: 0
        limit: 15
    }

    ...
    resultModel.executeQuery()
    ...

    ListView {
        id: suggestionList
        model: suggestionModel
        delegate: Text {
            text: 'Name: ' + searchResult.place.name }
        }
    }
    \endcode

    \sa SuggestionModel, SupportedCategoryModel, {QPlaceManager}
*/
QDeclarativeRecommendationModel::QDeclarativeRecommendationModel(QObject *parent) :
    QAbstractListModel(parent),
    m_manager(NULL),
    m_response(NULL)
{
    QHash<int, QByteArray> roleNames;
    roleNames = QAbstractItemModel::roleNames();
    roleNames.insert(SearchResultRole, "searchResult");
    setRoleNames(roleNames);
}

QDeclarativeRecommendationModel::~QDeclarativeRecommendationModel()
{
}

/*!
    \qmlsignal RecommenadationModel::queryFinished(const int &error)

    This handler is called when the request processing is finished.
    0 means that no error occurs during processing and new list is
    available.
*/

/*!
    \qmlproperty QDeclarativeListProperty<QDeclarativeSearchResult> RecommenadationModel::results

    This element holds the list of search results (place or "did you mean" strings)
    that the model currently has.
*/
QDeclarativeListProperty<QDeclarativeSearchResult> QDeclarativeRecommendationModel::results()
{
    return QDeclarativeListProperty<QDeclarativeSearchResult>(this,
                                                          0, // opaque data parameter
                                                          results_append,
                                                          results_count,
                                                          results_at,
                                                          results_clear);
}

void QDeclarativeRecommendationModel::results_append(QDeclarativeListProperty<QDeclarativeSearchResult> *prop,
                                                             QDeclarativeSearchResult* category)
{
    Q_UNUSED(prop);
    Q_UNUSED(category);
}

int QDeclarativeRecommendationModel::results_count(QDeclarativeListProperty<QDeclarativeSearchResult> *prop)
{
    return static_cast<QDeclarativeRecommendationModel*>(prop->object)->m_results.count();
}

QDeclarativeSearchResult* QDeclarativeRecommendationModel::results_at(QDeclarativeListProperty<QDeclarativeSearchResult> *prop,
                                                                          int index)
{
    QDeclarativeRecommendationModel* model = static_cast<QDeclarativeRecommendationModel*>(prop->object);
    QDeclarativeSearchResult *res = NULL;
    if (model->m_results.count() > index && index > -1) {
        res = model->m_results[index];
    }
    return res;
}

void QDeclarativeRecommendationModel::results_clear(QDeclarativeListProperty<QDeclarativeSearchResult> *prop)
{
    Q_UNUSED(prop)
}

void QDeclarativeRecommendationModel::convertResultsToDeclarative()
{
    qDeleteAll(m_results);
    m_results.clear();

    foreach (const QPlaceSearchResult& result, m_response->results()) {
        QDeclarativeSearchResult* declarative = new QDeclarativeSearchResult(result, this);
        m_results.append(declarative);
    }
}

int QDeclarativeRecommendationModel::rowCount(const QModelIndex& parent) const
{
    Q_UNUSED(parent);
    if (m_response) {
        return m_response->results().count();
    } else {
        return 0;
    }
}

// Returns the stored under the given role for the item referred to by the index.
QVariant QDeclarativeRecommendationModel::data(const QModelIndex& index, int role) const
{
    QDeclarativeSearchResult *result = NULL;
    if (m_response && m_response->results().count() > index.row()) {
       result = m_results[index.row()];
    }

    switch (role) {
        case Qt::DisplayRole:
            if (result && result->type() == QDeclarativeSearchResult::Place) {
                return result->place()->name();
            } else if (result && result->type() == QDeclarativeSearchResult::DidYouMeanSuggestion) {
                return result->didYouMeanSuggestion();
            } else {
                return QString();
            }
        case SearchResultRole:
            if (result) {
                return QVariant::fromValue(result);
            } else {
                return QVariant();
            }
        }
    return QVariant();
}

/*!
    \qmlproperty string RecommenadationModel::placeId

    This element holds place id used in query.
*/

QString QDeclarativeRecommendationModel::placeId() const
{
    return m_queryParameters.searchTerm();
}

void QDeclarativeRecommendationModel::setPlaceId(const QString &placeId)
{
    if (m_queryParameters.searchTerm() == placeId) {
        return;
    }
    m_queryParameters.setSearchTerm(placeId);
    emit placeIdChanged();
}

/*!
    \qmlproperty GeoCoordinate RecommenadationModel::searchCenter

    This element holds search center.

    Note: this property's changed() signal is currently emitted only if the
    whole element changes, not if only the contents of the element change.
*/
QDeclarativeCoordinate *QDeclarativeRecommendationModel::searchCenter()
{
    return &m_center;
}

void QDeclarativeRecommendationModel::setSearchCenter(QDeclarativeCoordinate *searchCenter)
{
    if (m_queryParameters.searchCenter() == searchCenter->coordinate()) {
        return;
    }
    m_queryParameters.setSearchCenter(searchCenter->coordinate());
    m_center.setCoordinate(m_queryParameters.searchCenter());
    emit searchCenterChanged();
}

/*!
    \qmlproperty GeoBoundingBox RecommenadationModel::boundingBox

    This element holds bounding box of text prediction search.

    Note: this property's changed() signal is currently emitted only if the
    whole element changes, not if only the contents of the element change.
*/
QDeclarativeGeoBoundingBox *QDeclarativeRecommendationModel::boundingBox()
{
    return &m_boundingBox;
}

void QDeclarativeRecommendationModel::setBoundingBox(QDeclarativeGeoBoundingBox *boundingBox)
{
    if (m_queryParameters.boundingBox() == boundingBox->box()) {
        return;
    }
    m_queryParameters.setBoundingBox(boundingBox->box());
    m_boundingBox.setBox(m_queryParameters.boundingBox());
    emit boundingBoxChanged();
}

/*!
    \qmlproperty int RecommenadationModel::offset

    This element holds offset for items that would be returned.
    Less then 0 means that it is undefined.
*/
int QDeclarativeRecommendationModel::offset() const
{
    return m_queryParameters.offset();
}

void QDeclarativeRecommendationModel::setOffset(const int &offsetValue)
{
    if (m_queryParameters.offset() == offsetValue){
        return;
    }
    m_queryParameters.setOffset(offsetValue);
    emit offsetChanged();
}

/*!
    \qmlproperty int RecommenadationModel::limit

    This element holds limit of items that would be returned.
    Less then -1 means that limit is undefined.
*/
int QDeclarativeRecommendationModel::limit() const
{
    return m_queryParameters.limit();
}

void QDeclarativeRecommendationModel::setLimit(const int &limit)
{
    if (m_queryParameters.limit() == limit){
        return;
    }
    m_queryParameters.setLimit(limit);
    emit limitChanged();
}

/*!
    \qmlmethod RecommenadationModel::executeQuery()
    Parameter placeId should contain string for which search should be
    started.
    Updates the items represented by the model from the underlying proivider.
*/
void QDeclarativeRecommendationModel::executeQuery()
{
    if (!m_manager) {
        m_manager = new QPlaceManager(this);
    }
    cancelPreviousRequest();
    beginResetModel();
    qDeleteAll(m_results);
    m_results.clear();
    endResetModel();
    emit resultsChanged();
    QPlace target;
    target.setPlaceId(m_queryParameters.searchTerm());
    connectNewResponse(m_manager->recommendations(target, m_queryParameters));
}

/*!
    \qmlmethod RecommenadationModel::cancelRequest()
    Cancels ongoing request.
*/
void QDeclarativeRecommendationModel::cancelRequest()
{
    cancelPreviousRequest();
}

void QDeclarativeRecommendationModel::replyFinished()
{
    if (m_response && m_response->results().count()) {
        beginResetModel();
        convertResultsToDeclarative();
        endResetModel();
        emit resultsChanged();
    }
    emit queryFinished(0);
}

void QDeclarativeRecommendationModel::replyError(QPlaceReply::Error error,
                                                 const QString &errorString)
{
    Q_UNUSED(error);
    Q_UNUSED(errorString);

    emit queryFinished(-1);
}

void QDeclarativeRecommendationModel::cancelPreviousRequest()
{
    if (m_response) {
        if (!m_response->isFinished()) {
            m_response->abort();
        }
        m_response->deleteLater();
        m_response = NULL;
    }
}

void QDeclarativeRecommendationModel::connectNewResponse(QPlaceSearchReply *newResponse)
{
    if (newResponse) {
        m_response = newResponse;
        m_response->setParent(this);
        connect(m_response, SIGNAL(finished()), this, SLOT(replyFinished()));
        connect(m_response, SIGNAL(error(QPlaceReply::Error,QString)),
                this, SLOT(replyError(QPlaceReply::Error,QString)));
    } else {
        emit queryFinished(-1);
    }
}