diff --git a/Map/GeoCoordinates.h b/Map/GeoCoordinates.h
index ce5f88c7..280e906e 100644
--- a/Map/GeoCoordinates.h
+++ b/Map/GeoCoordinates.h
@@ -1,63 +1,63 @@
/* Copyright (C) 2018 The KPhotoAlbum Development Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef GEOCOORDINATES_H
#define GEOCOORDINATES_H
#include
#include
#include
namespace Map
{
class GeoCoordinates
{
public:
bool hasCoordinates() const;
double lon() const;
double lat() const;
double alt() const;
bool hasAltitude() const;
void setLatLon(const double lat, const double lon);
void setAlt(const double alt);
typedef QPair Pair;
static Pair makePair(const double lat1, const double lon1,
const double lat2, const double lon2);
operator QString() const;
private: // Variables
double m_lat;
double m_lon;
double m_alt;
- bool m_hasCoordinates;
- bool m_hasAlt;
+ bool m_hasCoordinates = false;
+ bool m_hasAlt = false;
};
}
Q_DECLARE_METATYPE(Map::GeoCoordinates::Pair)
#endif // GEOCOORDINATES_H
// vi:expandtab:tabstop=4 shiftwidth=4:
diff --git a/Map/MapView.cpp b/Map/MapView.cpp
index 13f984d9..97e4d960 100644
--- a/Map/MapView.cpp
+++ b/Map/MapView.cpp
@@ -1,312 +1,325 @@
/* Copyright (C) 2014-2018 The KPhotoAlbum Development Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
// Local includes
#include "MapView.h"
#include "Logging.h"
+#include "ImageManager/ThumbnailCache.h"
+#include "Utilities/Util.h"
// Marble includes
#include
#include
#include
// Qt includes
#include
#include
#include
#include
#include
#include
#include
// KDE includes
#include
#include
#include
#include
#include
namespace {
const QString MAPVIEW_FLOATER_VISIBLE_CONFIG_PREFIX = QStringLiteral("MarbleFloaterVisible ");
const QStringList MAPVIEW_RENDER_POSITION({QStringLiteral("HOVERS_ABOVE_SURFACE")});
}
Map::MapView::MapView(QWidget *parent, UsageType type) : QWidget(parent)
{
if (type == MapViewWindow) {
setWindowFlags(Qt::Window);
setAttribute(Qt::WA_DeleteOnClose);
}
QVBoxLayout *layout = new QVBoxLayout(this);
m_statusLabel = new QLabel;
m_statusLabel->setAlignment(Qt::AlignCenter);
- m_statusLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_statusLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_statusLabel->hide();
layout->addWidget(m_statusLabel);
m_mapWidget = new Marble::MarbleWidget;
m_mapWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_mapWidget->setProjection(Marble::Mercator);
m_mapWidget->setMapThemeId(QStringLiteral("earth/openstreetmap/openstreetmap.dgml"));
m_mapWidget->addLayer(this);
layout->addWidget(m_mapWidget);
m_mapWidget->show();
QHBoxLayout *controlLayout = new QHBoxLayout;
layout->addLayout(controlLayout);
// KPA's control buttons
- QWidget *kpaButtons = new QWidget;
- QHBoxLayout *kpaButtonsLayout = new QHBoxLayout(kpaButtons);
- controlLayout->addWidget(kpaButtons);
+ m_kpaButtons = new QWidget;
+ QHBoxLayout *kpaButtonsLayout = new QHBoxLayout(m_kpaButtons);
+ controlLayout->addWidget(m_kpaButtons);
QPushButton *saveButton = new QPushButton;
saveButton->setFlat(true);
saveButton->setIcon(QPixmap(SmallIcon(QStringLiteral("media-floppy"))));
saveButton->setToolTip(i18n("Save the current map settings"));
kpaButtonsLayout->addWidget(saveButton);
connect(saveButton, &QPushButton::clicked, this, &MapView::saveSettings);
m_setLastCenterButton = new QPushButton;
m_setLastCenterButton->setFlat(true);
m_setLastCenterButton->setIcon(QPixmap(SmallIcon(QStringLiteral("go-first"))));
m_setLastCenterButton->setToolTip(i18n("Go to last map position"));
kpaButtonsLayout->addWidget(m_setLastCenterButton);
connect(m_setLastCenterButton, &QPushButton::clicked, this, &MapView::setLastCenter);
+ QPushButton *showThumbnails = new QPushButton;
+ showThumbnails->setFlat(true);
+ showThumbnails->setIcon(QPixmap(SmallIcon(QStringLiteral("view-preview"))));
+ showThumbnails->setToolTip(i18n("Show thumbnails"));
+ kpaButtonsLayout->addWidget(showThumbnails);
+ m_showThumbnails = true;
+ showThumbnails->setCheckable(true);
+ showThumbnails->setChecked(true);
+ connect(showThumbnails, &QPushButton::clicked, this, &MapView::setShowThumbnails);
+
// Marble floater control buttons
m_floaters = new QWidget;
QHBoxLayout *floatersLayout = new QHBoxLayout(m_floaters);
controlLayout->addStretch();
controlLayout->addWidget(m_floaters);
KSharedConfigPtr config = KSharedConfig::openConfig();
KConfigGroup group = config->group(QStringLiteral("MapView"));
for (const Marble::RenderPlugin *plugin : m_mapWidget->renderPlugins()) {
if (plugin->renderType() != Marble::RenderPlugin::PanelRenderType) {
continue;
}
QPushButton *button = new QPushButton;
button->setCheckable(true);
button->setFlat(true);
button->setChecked(plugin->action()->isChecked());
button->setToolTip(plugin->description());
const QString name = plugin->name();
button->setProperty("floater", name);
QPixmap icon = plugin->action()->icon().pixmap(QSize(20, 20));
if (icon.isNull()) {
icon = QPixmap(20, 20);
icon.fill(Qt::white);
}
button->setIcon(icon);
connect(plugin->action(), &QAction::toggled, button, &QPushButton::setChecked);
connect(button, &QPushButton::toggled, plugin->action(), &QAction::setChecked);
floatersLayout->addWidget(button);
const QString value = group.readEntry(MAPVIEW_FLOATER_VISIBLE_CONFIG_PREFIX + name);
if (! value.isEmpty()) {
button->setChecked(value == QStringLiteral("true") ? true : false);
}
}
+
+ m_pin = QPixmap(Utilities::locateDataFile(QStringLiteral("pics/pin.png")));
}
void Map::MapView::clear()
{
m_images.clear();
m_markersBox.clear();
}
void Map::MapView::addImage(DB::ImageInfoPtr image)
{
- if (! image->coordinates().hasCoordinates()) {
- qCDebug(MapLog) << "Image" << image->label() << "has no geo coordinates";
- return;
- }
-
qCDebug(MapLog) << "Adding image" << image->label();
m_images.append(image);
// Update the viewport for zoomToMarkers()
if (m_markersBox.isEmpty()) {
m_markersBox.setEast(image->coordinates().lon(), Marble::GeoDataCoordinates::Degree);
m_markersBox.setWest(image->coordinates().lon(), Marble::GeoDataCoordinates::Degree);
m_markersBox.setNorth(image->coordinates().lat(), Marble::GeoDataCoordinates::Degree);
m_markersBox.setSouth(image->coordinates().lat(), Marble::GeoDataCoordinates::Degree);
} else {
if (m_markersBox.east(Marble::GeoDataCoordinates::Degree) < image->coordinates().lon()) {
m_markersBox.setEast(image->coordinates().lon(), Marble::GeoDataCoordinates::Degree);
}
if (m_markersBox.west(Marble::GeoDataCoordinates::Degree) > image->coordinates().lon()) {
m_markersBox.setWest(image->coordinates().lon(), Marble::GeoDataCoordinates::Degree);
}
if (m_markersBox.north(Marble::GeoDataCoordinates::Degree) < image->coordinates().lat()) {
m_markersBox.setNorth(image->coordinates().lat(), Marble::GeoDataCoordinates::Degree);
}
if (m_markersBox.south(Marble::GeoDataCoordinates::Degree) > image->coordinates().lat()) {
m_markersBox.setSouth(image->coordinates().lat(), Marble::GeoDataCoordinates::Degree);
}
}
}
void Map::MapView::zoomToMarkers()
{
m_mapWidget->centerOn(m_markersBox);
}
void Map::MapView::setCenter(const DB::ImageInfoPtr image)
{
m_lastCenter = image->coordinates();
setLastCenter();
}
void Map::MapView::saveSettings()
{
KSharedConfigPtr config = KSharedConfig::openConfig();
KConfigGroup group = config->group(QStringLiteral("MapView"));
for (const QPushButton *button : m_floaters->findChildren()) {
group.writeEntry(MAPVIEW_FLOATER_VISIBLE_CONFIG_PREFIX
+ button->property("floater").toString(), button->isChecked());
}
config->sync();
QMessageBox::information(this, i18n("Map view"), i18n("Settings saved!"));
}
void Map::MapView::setShowThumbnails(bool state)
{
- Q_UNUSED(state);
- qDebug() << ">>> Implement me! Map::MapView::setShowThumbnails(bool state)";
+ m_showThumbnails = state;
+ m_mapWidget->reloadMap();
}
void Map::MapView::displayStatus(MapStatus status)
{
switch (status) {
case MapStatus::Loading:
m_statusLabel->setText(i18n("Loading coordinates from the images ..."));
m_statusLabel->show();
m_mapWidget->hide();
//m_mapWidget->clearRegionSelection();
m_setLastCenterButton->setEnabled(false);
break;
case MapStatus::ImageHasCoordinates:
m_statusLabel->hide();
//m_mapWidget->setAvailableMouseModes(KGeoMap::MouseModePan);
//m_mapWidget->setVisibleMouseModes(0);
//m_mapWidget->setMouseMode(KGeoMap::MouseModePan);
//m_mapWidget->clearRegionSelection();
m_mapWidget->show();
m_setLastCenterButton->show();
m_setLastCenterButton->setEnabled(true);
break;
case MapStatus::ImageHasNoCoordinates:
m_statusLabel->setText(i18n("This image does not contain geographic coordinates."));
m_statusLabel->show();
m_mapWidget->hide();
m_setLastCenterButton->show();
m_setLastCenterButton->setEnabled(false);
break;
case MapStatus::SomeImagesHaveNoCoordinates:
m_statusLabel->setText(i18n("Some of the selected images do not contain geographic "
"coordinates."));
m_statusLabel->show();
//m_mapWidget->setAvailableMouseModes(KGeoMap::MouseModePan);
//m_mapWidget->setVisibleMouseModes(0);
//m_mapWidget->setMouseMode(KGeoMap::MouseModePan);
//m_mapWidget->clearRegionSelection();
m_mapWidget->show();
m_setLastCenterButton->show();
m_setLastCenterButton->setEnabled(true);
break;
case MapStatus::SearchCoordinates:
m_statusLabel->setText(i18n("Search for geographic coordinates."));
m_statusLabel->show();
//m_mapWidget->setAvailableMouseModes(KGeoMap::MouseModePan
// | KGeoMap::MouseModeRegionSelectionFromIcon
// | KGeoMap::MouseModeRegionSelection);
//m_mapWidget->setVisibleMouseModes(KGeoMap::MouseModePan
// | KGeoMap::MouseModeRegionSelectionFromIcon
// | KGeoMap::MouseModeRegionSelection);
//m_mapWidget->setMouseMode(KGeoMap::MouseModeRegionSelectionFromIcon);
m_mapWidget->show();
- //m_mapWidget->setCenter(KGeoMap::GeoCoordinates());
+ m_mapWidget->centerOn(0.0, 0.0);
m_setLastCenterButton->hide();
break;
case MapStatus::NoImagesHaveNoCoordinates:
m_statusLabel->setText(i18n("None of the selected images contain geographic "
"coordinates."));
m_statusLabel->show();
m_mapWidget->hide();
m_setLastCenterButton->show();
m_setLastCenterButton->setEnabled(false);
break;
}
emit displayStatusChanged(status);
}
void Map::MapView::setLastCenter()
{
m_mapWidget->centerOn(m_lastCenter.lon(), m_lastCenter.lat());
}
Map::GeoCoordinates::Pair Map::MapView::getRegionSelection() const
{
qDebug() << ">>> Implement me! Map::MapView::getRegionSelection()";
return GeoCoordinates::makePair(0, 0, 0, 0);
}
bool Map::MapView::regionSelected() const
{
qDebug() << ">>> Implement me! Map::MapView::regionSelected()";
return false;
}
QStringList Map::MapView::renderPosition() const
{
// we only ever paint on the same layer:
return MAPVIEW_RENDER_POSITION;
}
bool Map::MapView::render(Marble::GeoPainter *painter, Marble::ViewportParams *,
const QString &renderPos, Marble::GeoSceneLayer *)
{
Q_ASSERT(renderPos == renderPosition().first());
- painter->setRenderHint(QPainter::Antialiasing, true);
- painter->setPen(QPen(QBrush(QColor::fromRgb(255, 0, 0)), 3.0, Qt::SolidLine, Qt::RoundCap));
-
for (const DB::ImageInfoPtr &image: m_images) {
const Marble::GeoDataCoordinates pos(image->coordinates().lon(), image->coordinates().lat(),
image->coordinates().alt(),
Marble::GeoDataCoordinates::Degree);
- painter->drawAnnotation(pos, image->label());
+ if (m_showThumbnails) {
+ // FIXME(l3u) Maybe we should cache the scaled thumbnails?
+ painter->drawPixmap(pos, ImageManager::ThumbnailCache::instance()->lookup(
+ image->fileName()).scaled(QSize(40, 40),
+ Qt::KeepAspectRatio));
+ } else {
+ painter->drawPixmap(pos, m_pin);
+ }
}
return true;
}
// vi:expandtab:tabstop=4 shiftwidth=4:
diff --git a/Map/MapView.h b/Map/MapView.h
index f53992a0..44842291 100644
--- a/Map/MapView.h
+++ b/Map/MapView.h
@@ -1,166 +1,171 @@
/* Copyright (C) 2014-2018 The KPhotoAlbum Development Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef MAPVIEW_H
#define MAPVIEW_H
// Local includes
#include "GeoCoordinates.h"
#include "DB/ImageInfo.h"
#include "DB/ImageInfoPtr.h"
-// Qt includes
-#include
-#include
-
// Marble includes
#include
#include
#include
+// Qt includes
+#include
+#include
+#include
+
// Marble classes
namespace Marble
{
class MarbleWidget;
}
// Qt classes
class QLabel;
class QPushButton;
namespace Map
{
class MapView
: public QWidget
, public Marble::LayerInterface
{
Q_OBJECT
public:
/**
* UsageType: determines whether the widget is used as a standalone widget
* or within another widget (e.g. the AnnotationDialog).
* @see Viewer::ViewerWidget::UsageType
*/
enum UsageType {
InlineMapView,
MapViewWindow
};
/**
* MapStatus: determines the visibility and text of the status label and the visibility of the
* map, depending on the availability of coordinates of the image(s) that are displayed.
*/
enum MapStatus {
Loading,
ImageHasCoordinates,
ImageHasNoCoordinates,
NoImagesHaveNoCoordinates,
SomeImagesHaveNoCoordinates,
SearchCoordinates
};
explicit MapView(QWidget *parent = nullptr, UsageType type = InlineMapView);
~MapView() = default;
/**
* Removes all images from the map.
*/
void clear();
/**
* Add an image to the map.
*/
void addImage(DB::ImageInfoPtr image);
/**
* Sets the map's zoom so that all images on the map are visible.
* If no images have been added, the zoom is not altered.
*/
void zoomToMarkers();
/**
* Sets the state of the "Show Thumbnails" button on the map's control widget.
*/
void setShowThumbnails(bool state);
/**
* This sets the status label text and it's visibility, as well as the visibilty of the map
* itself to the state indicated by the given MapStatus.
*/
void displayStatus(MapStatus status);
GeoCoordinates::Pair getRegionSelection() const;
bool regionSelected() const;
// LayerInterface:
/**
* @brief renderPosition tells the LayerManager what layers we (currently) want to paint on.
* Part of the LayerInterface; called by the LayerManager.
* @return
*/
QStringList renderPosition() const override;
/**
* @brief Render all markers onto the marbleWidget.
* Part of the LayerInterface; called by the LayerManager.
* @param painter the painter used by the LayerManager
* @param viewport
* @param renderPos the layer name
* @param layer always \c nullptr
* @return \c true (return value is discarded by LayerManager::renderLayers())
*/
bool render(Marble::GeoPainter *painter, Marble::ViewportParams *,
const QString &renderPos, Marble::GeoSceneLayer *) override;
Q_SIGNALS:
void signalRegionSelectionChanged();
void displayStatusChanged(MapStatus);
public slots:
/**
* Centers the map on the coordinates of the given image.
*/
void setCenter(const DB::ImageInfoPtr image);
private slots:
void saveSettings();
void setLastCenter();
private: // Variables
Marble::MarbleWidget *m_mapWidget;
QLabel *m_statusLabel;
QPushButton *m_setLastCenterButton;
GeoCoordinates m_lastCenter;
+ QWidget *m_kpaButtons;
QWidget *m_floaters;
// FIXME(jzarl): dirty hack to get it working
// if this should work efficiently with a large number of images,
// some spatially aware data structure probably needs to be used
// (e.g. binning images by location)
QList m_images;
Marble::GeoDataLatLonBox m_markersBox;
+ bool m_showThumbnails;
+ QPixmap m_pin;
+
};
}
#endif // MAPVIEW_H
// vi:expandtab:tabstop=4 shiftwidth=4:
diff --git a/images/CMakeLists.txt b/images/CMakeLists.txt
index 61b96254..0314338d 100644
--- a/images/CMakeLists.txt
+++ b/images/CMakeLists.txt
@@ -1,11 +1,12 @@
install(
FILES
multiconfig.jpg
search.jpg
splash.png
splash-large.png
movie-clip.png
+ pin.png
DESTINATION ${KDE_INSTALL_DATADIR}/kphotoalbum/pics
)
# vi:expandtab:tabstop=4 shiftwidth=4:
diff --git a/images/pin.png b/images/pin.png
new file mode 100644
index 00000000..3e9c6ab6
Binary files /dev/null and b/images/pin.png differ
diff --git a/images/pin.svg b/images/pin.svg
new file mode 100644
index 00000000..33abc750
--- /dev/null
+++ b/images/pin.svg
@@ -0,0 +1,119 @@
+
+
+
+