Skip to content

Commit 3a3f4e4

Browse files
committed
Merge branch 'master' into release
2 parents 6916564 + 99c418c commit 3a3f4e4

File tree

69 files changed

+3057
-2601
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+3057
-2601
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ endif()
2929

3030
# Project declaration
3131

32-
project(Mapper VERSION 0.8.2 LANGUAGES CXX C)
32+
project(Mapper VERSION 0.8.3 LANGUAGES CXX C)
3333

3434
if(Mapper_VERSION_DISPLAY)
3535
message(STATUS "Custom version display string: \"${Mapper_VERSION_DISPLAY}\"")

android/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0"?>
2-
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.8.2" android:versionCode="802" package="org.openorienteering.mapper" android:installLocation="auto">
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="0.8.3" android:versionCode="803" package="org.openorienteering.mapper" android:installLocation="auto">
33
<application android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="@string/long_app_name" android:icon="@drawable/icon">
44
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|locale|fontScale|keyboard|keyboardHidden|navigation"
55
android:name="org.openorienteering.mapper.MapperActivity"

code-check-wrapper.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ PATTERN=" \
5252
file_import_export.cpp \
5353
georeferencing_dialog.cpp \
5454
gdal_manager.cpp \
55+
gps_display.cpp \
5556
key_button_bar.cpp \
5657
/map.cpp \
5758
map_editor.cpp \

doc/manual/pages/android-app.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,28 @@ Note that the temporary trace is not saved in the map.
127127
This removes the temporay traces and position markers. (They will also be discarded when closing the map file.)
128128

129129

130+
#### ![ ](../mapper-images/pencil.png) Paint on template
131+
132+
By this tool, mapper supports free-hand drawing onto image templates. There is
133+
a small selection of colors for drawing. White is used for corrections to
134+
previous drawings. There is also a dedicated undo/redo feature.
135+
136+
This tool is an convenient alternative when you want to do only (or mostly)
137+
drafting in the field, but draw the final version of the map at home on a PC.
138+
It does not create new map objects but only alters the template you draw on.
139+
This may help to deal with low processing power or battery runtime on mobile
140+
devices.
141+
142+
Please note that direct drawing onto base map images is *not* recommended:
143+
First, the eraser tool would also erase the base map. Second, these images
144+
usually are in the lossy JPEG format which will introduce visible artifacts
145+
when saving the file and loading it repeatedly.
146+
147+
130148
#### ![ ](../mapper-images/paint-on-template-settings.png) Paint-on-template settings
131149

132-
This button allows to select the active image for scribbling (using the symbol above it).
150+
This button allows to select an image template for scribbling,
151+
or to add a new one covering the vicinity of your position.
133152

134153

135154
-----

doc/manual/pages/android-pc.md

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,3 @@ In this case, the easiest way is to first create a new map with the same symbol
2323
After that, load the existing map as template in the new map. Then use the alignment tools for templates to move the existing map to match with the new georeferenced template. When you are finished, import the existing map template into the new map file using the corresponding action in the template dock widget, and you should be done.
2424

2525
Attention: especially for old maps, the whole existing map may be locally distorted. In this case it will not be possible to match the old map and the georeferenced template and the only way to georeference the map is to do a tedious undistortion. Mapper does not provide a tool for this.
26-
27-
28-
## Preparing for free-hand scribbling
29-
30-
![ ](../mapper-images/pencil.png)
31-
32-
Mapper supports free-hand drawing onto image templates using the tool with the pencil icon shown above. This is especially convenient to use in case you want to do only (or mostly) drafting while you are in the field, and draw the final version of the map at home on a PC. It has the advantage of being quick and it only alters the template you draw on, i.e. it does not create new map objects, so Mapper's map display does not become slower. This may be relevant on mobile devices because of little processing power or because of battery runtime.
33-
34-
If you want to use this functionality, you should best load a separate, initially transparent image template in png format for it. Suited images can be downloaded here:
35-
36-
- [size 1024x1024](attachment/scribble_1024.png)
37-
- [size 2048x2048](attachment/scribble_2048.png)
38-
39-
The images contain a red border, but are transparent everywhere else. After downloading a file, load it in your map file and move it so it covers the area you want to draw scribbles on. Make sure that the image resolution of the template is good enough by drawing a test scribble. If not, you need to scale it down using the template settings. You may also create multiple copies of the file and load them as separate templates.
40-
41-
Direct drawing onto base map images is NOT recommended because you will not be able to use the eraser without also erasing the base map and because these images usually are in the lossy JPEG format which will introduce visible artifacts when saving the file and loading it again.
42-
43-
Note that to view the scribbles on a PC after creating them on a mobile device, you need to transfer not only the map file, but also the affected image template file(s) back to the PC, as the scribbles are saved directly in the image files.

doc/manual/pages/android-storage.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,25 @@ OpenOrienteering Mapper for Android will create these folders when they are miss
2727
You can transfer files from and to a PC via a USB cable. Android supports multiple file transfer protocols.
2828

2929
- MTP is the preferred method now. There is hardly any interference for apps while the device is connected to the PC.
30-
Via MTP, Android will only show files which are known to its Media Scanner. If you cannot find a file such a recorded GPX track, a reboot of the device could trigger a rescan.
30+
Via MTP, Android will only show files which are known to its Media Scanner.
3131

3232
- Mass Storage makes the storage unavailable for apps for the duration of the connection with the PC.
3333
(Android also needs to terminate apps which are stored on the volume which is provided as mass storage.)
3434
Unlike MTP, mass storage does not depend on the media scanner, so all files are always visible.
3535

36-
In some cases, users suffered from files being damaged during transfer. This can be worked around by choosing another method for file transfer. Remember to keep backups and to verify transferred files.
36+
Note that after mapping, you might want to transfer back not only the modified map but also GPX tracks and templates you painted on.
37+
38+
39+
## Data loss prevention and recovery
40+
41+
*Remember to keep backups and to verify transferred files.*
42+
43+
If a file appears to be corrupted after transfer back to PC, or you cannot find
44+
a new file such as a recorded GPX track, a reboot of the Android device could
45+
solve the issue. After the reboot, Android's media scanner will take notice of
46+
new files and changed file sizes. However, Mapper v0.8.3 is expected to bring a
47+
solution to this issue.
48+
49+
In some situations, the Mapper app might not be able to properly save data and
50+
shutdown as quickly as requested by the Android operating system, for example
51+
when you start other apps or when the device runs out of power.
-9.72 KB
Loading

src/core/map.cpp

Lines changed: 24 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@
7878

7979
// IWYU pragma: no_forward_declare QRectF
8080

81+
#ifdef Q_OS_ANDROID
82+
#include "core/storage_location.h"
83+
#endif
84+
8185

8286
namespace OpenOrienteering {
8387

@@ -694,6 +698,15 @@ bool Map::exportTo(const QString& path, MapView* view, const FileFormat* format)
694698
}
695699

696700
success = file.commit();
701+
#ifdef Q_OS_ANDROID
702+
if (success)
703+
{
704+
// Make the MediaScanner aware of the *updated* file. This is an
705+
// attempt to resolve issues with files being transferred
706+
// incompletely to the PC (#1115).
707+
Android::mediaScannerScanFile(QFileInfo(path).absolutePath());
708+
}
709+
#endif
697710
}
698711

699712
if (!success)
@@ -2239,96 +2252,45 @@ void Map::setCurrentPartIndex(std::size_t index)
22392252
}
22402253
}
22412254

2242-
std::size_t Map::reassignObjectsToMapPart(std::set<Object*>::const_iterator begin, std::set<Object*>::const_iterator end, std::size_t source, std::size_t destination)
2243-
{
2244-
Q_ASSERT(source < parts.size());
2245-
Q_ASSERT(destination < parts.size());
2246-
2247-
std::size_t count = 0;
2248-
MapPart* const source_part = parts[source];
2249-
MapPart* const target_part = parts[destination];
2250-
for (auto it = begin; it != end; ++it)
2251-
{
2252-
Object* const object = *it;
2253-
source_part->deleteObject(object, true);
2254-
2255-
int index = target_part->getNumObjects();
2256-
target_part->addObject(object, index);
2257-
2258-
++count;
2259-
}
2260-
2261-
setOtherDirty();
2262-
2263-
std::size_t const target_end = target_part->getNumObjects();
2264-
std::size_t const target_begin = target_end - count;
2265-
2266-
if (current_part_index == source)
2267-
{
2268-
int const selection_size = getNumSelectedObjects();
2269-
2270-
// When modifying the selection we must not use the original iterators
2271-
// because they may be operating on the selection and then become invalid!
2272-
for (std::size_t i = target_begin; i != target_end; ++i)
2273-
{
2274-
Object* const object = target_part->getObject(i);
2275-
if (isObjectSelected(object))
2276-
removeObjectFromSelection(object, false);
2277-
}
2278-
2279-
if (selection_size != getNumSelectedObjects())
2280-
emit objectSelectionChanged();
2281-
}
2282-
2283-
return target_begin;
2284-
}
2285-
2286-
std::size_t Map::reassignObjectsToMapPart(std::vector<int>::const_iterator begin, std::vector<int>::const_iterator end, std::size_t source, std::size_t destination)
2255+
int Map::reassignObjectsToMapPart(std::vector<int>::const_iterator first, std::vector<int>::const_iterator last, std::size_t source, std::size_t destination)
22872256
{
22882257
Q_ASSERT(source < parts.size());
22892258
Q_ASSERT(destination < parts.size());
22902259

2291-
bool selection_changed = false;
2292-
2293-
std::size_t count = 0;
22942260
MapPart* const source_part = parts[source];
22952261
MapPart* const target_part = parts[destination];
2296-
for (auto it = begin; it != end; ++it)
2262+
auto first_object = target_part->getNumObjects();
2263+
auto selection_size = getNumSelectedObjects();
2264+
for (auto it = first; it != last; ++it)
22972265
{
2266+
Q_ASSERT(*it < source_part->getNumObjects());
22982267
Object* const object = source_part->getObject(*it);
22992268

23002269
if (current_part_index == source && isObjectSelected(object))
2301-
{
23022270
removeObjectFromSelection(object, false);
2303-
selection_changed = true;
2304-
}
23052271

23062272
source_part->deleteObject(object, true);
2307-
2308-
int index = target_part->getNumObjects();
2309-
target_part->addObject(object, index);
2310-
2311-
++count;
2273+
target_part->addObject(object);
23122274
}
23132275

23142276
setOtherDirty();
23152277

2316-
if (selection_changed)
2278+
if (getNumSelectedObjects() != selection_size)
23172279
emit objectSelectionChanged();
23182280

2319-
return target_part->getNumObjects() - count;
2281+
return first_object;
23202282
}
23212283

2322-
std::size_t Map::mergeParts(std::size_t source, std::size_t destination)
2284+
int Map::mergeParts(std::size_t source, std::size_t destination)
23232285
{
23242286
Q_ASSERT(source < parts.size());
23252287
Q_ASSERT(destination < parts.size());
23262288

2327-
std::size_t count = 0;
2289+
int count = 0;
23282290
MapPart* const source_part = parts[source];
23292291
MapPart* const target_part = parts[destination];
23302292
// Preserve order (but not efficient)
2331-
for (std::size_t i = source_part->getNumObjects(); i > 0 ; --i)
2293+
for (auto i = source_part->getNumObjects(); i > 0 ; --i)
23322294
{
23332295
Object* object = source_part->getObject(0);
23342296
source_part->deleteObject(0, true);

src/core/map.h

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -799,25 +799,19 @@ public slots:
799799
*/
800800
void setCurrentPartIndex(std::size_t index);
801801

802-
/**
803-
* Moves all specified objects from the source to the destination map part.
804-
*
805-
* The objects will be continuously located at the end to the objects in the target part.
806-
* Source object which were selected will be removed from the object selection.
807-
*
808-
* @return The index of the first object which has been reassigned.
809-
*/
810-
std::size_t reassignObjectsToMapPart(std::set<Object*>::const_iterator begin, std::set<Object*>::const_iterator end, std::size_t source, std::size_t destination);
811-
812802
/**
813803
* Moves all specified objects from the source to the target map part.
814804
*
805+
* Objects are processed one by one. This means that processing one object
806+
* changes the index of following objects. Thus the given indices must
807+
* normally be in descending order.
808+
*
815809
* The objects will be continuously located at the end to the objects in the target part.
816810
* Source object which were selected will be removed from the object selection.
817811
*
818812
* @return The index of the first object which has been reassigned.
819813
*/
820-
std::size_t reassignObjectsToMapPart(std::vector<int>::const_iterator begin, std::vector<int>::const_iterator end, std::size_t source, std::size_t destination);
814+
int reassignObjectsToMapPart(std::vector<int>::const_iterator first, std::vector<int>::const_iterator last, std::size_t source, std::size_t destination);
821815

822816
/**
823817
* Merges the source part with the destination part.
@@ -831,7 +825,7 @@ public slots:
831825
*
832826
* @return The index of the first object which has been reassigned.
833827
*/
834-
std::size_t mergeParts(std::size_t source, std::size_t destination);
828+
int mergeParts(std::size_t source, std::size_t destination);
835829

836830

837831
// Objects

src/core/storage_location.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,8 @@ namespace Android {
4848
*/
4949
static std::shared_ptr<const std::vector<StorageLocation>> locations_cache;
5050

51-
/**
52-
* Tells the media scanner to register the given file or folder.
53-
*
54-
* This is required to make files quickly available for transfer via MTP.
55-
*/
56-
void mediaScannerScanFile(const QString path)
51+
52+
void mediaScannerScanFile(const QString& path)
5753
{
5854
static const auto ACTION_MEDIA_SCANNER_SCAN_FILE =
5955
QAndroidJniObject::getStaticObjectField<jstring>("android/content/Intent",
@@ -285,7 +281,7 @@ QString StorageLocation::fileHintTextTemplate(Hint hint)
285281
switch (hint)
286282
{
287283
case HintNormal:
288-
return tr("'%1' is stored in a regular location.");
284+
return {}; // No text for a regular location.
289285

290286
case HintApplication:
291287
return tr("'%1' is located in app storage. The files will be removed when uninstalling the app.");
@@ -301,4 +297,10 @@ QString StorageLocation::fileHintTextTemplate(Hint hint)
301297
}
302298

303299

300+
QString OpenOrienteering::StorageLocation::hintText() const
301+
{
302+
return hint() == HintNormal ? QString{} : fileHintTextTemplate(hint()).arg(path());
303+
}
304+
305+
304306
} // namespace OpenOrienteering

0 commit comments

Comments
 (0)