Store user marks and tracks inside the BookmarkManager.

This commit is contained in:
Daria Volvenkova 2018-02-01 18:17:57 +03:00 committed by Roman Kuznetsov
parent 79daba4551
commit 0d0c91cf7d
39 changed files with 1140 additions and 1262 deletions

View file

@ -373,14 +373,14 @@ void Framework::RemoveLocalMaps()
m_work.DeregisterAllMaps();
}
void Framework::ReplaceBookmark(BookmarkAndCategory const & ind, BookmarkData & bm)
void Framework::ReplaceBookmark(df::MarkID markId, BookmarkData & bm)
{
m_work.ReplaceBookmark(ind.m_categoryIndex, ind.m_bookmarkIndex, bm);
m_work.ReplaceBookmark(markId, ind.m_bookmarkIndex, bm);
}
size_t Framework::ChangeBookmarkCategory(BookmarkAndCategory const & ind, size_t newCat)
size_t Framework::ChangeBookmarkCategory(df::MarkID markId, df::MarkGroupID newCat)
{
return m_work.MoveBookmark(ind.m_bookmarkIndex, ind.m_categoryIndex, newCat);
return m_work.MoveBookmark(markId, newCat);
}
bool Framework::ShowMapForURL(string const & url)

View file

@ -138,8 +138,8 @@ namespace android
void Scale(::Framework::EScaleMode mode);
void Scale(m2::PointD const & centerPt, int targetZoom, bool animate);
void ReplaceBookmark(BookmarkAndCategory const & ind, BookmarkData & bm);
size_t ChangeBookmarkCategory(BookmarkAndCategory const & ind, size_t newCat);
void ReplaceBookmark(df::MarkID markId, BookmarkData & bm);
size_t ChangeBookmarkCategory(df::MarkID markId, df::MarkGroupID newCat);
::Framework * NativeFramework();

View file

@ -227,13 +227,14 @@ void DrapeEngine::UpdateUserMarksGroup(MarkGroupID groupId, UserMarksProvider *
auto removedIdCollection = make_unique_dp<MarkIDCollection>();
auto createdIdCollection = make_unique_dp<MarkIDCollection>();
auto marksRenderCollection = make_unique_dp<UserMarksRenderCollection>();
marksRenderCollection->reserve(provider->GetUserPointCount());
provider->AcceptChanges(groupId, *groupIdCollection, *createdIdCollection, *removedIdCollection);
for (size_t pointIndex = 0, sz = provider->GetUserPointCount(); pointIndex < sz; ++pointIndex)
auto marksRenderCollection = make_unique_dp<UserMarksRenderCollection>();
marksRenderCollection->reserve(groupIdCollection->m_marksID.size());
for (auto markId : groupIdCollection->m_marksID)
{
UserPointMark const * mark = provider->GetUserPointMark(pointIndex);
groupIdCollection->m_marksID.push_back(mark->GetId());
UserPointMark const * mark = provider->GetUserPointMark(markId);
if (mark->IsDirty())
{
auto renderInfo = make_unique_dp<UserMarkRenderParams>();
@ -263,11 +264,10 @@ void DrapeEngine::UpdateUserMarksGroup(MarkGroupID groupId, UserMarksProvider *
}
auto linesRenderCollection = make_unique_dp<UserLinesRenderCollection>();
linesRenderCollection->reserve(provider->GetUserLineCount());
for (size_t lineIndex = 0, sz = provider->GetUserLineCount(); lineIndex < sz; ++lineIndex)
linesRenderCollection->reserve(groupIdCollection->m_linesID.size());
for (auto lineId : groupIdCollection->m_linesID)
{
UserLineMark const * mark = provider->GetUserLineMark(lineIndex);
groupIdCollection->m_linesID.push_back(mark->GetId());
UserLineMark const * mark = provider->GetUserLineMark(lineId);
if (mark->IsDirty())
{
auto renderInfo = make_unique_dp<UserLineRenderParams>();
@ -287,8 +287,6 @@ void DrapeEngine::UpdateUserMarksGroup(MarkGroupID groupId, UserMarksProvider *
}
}
provider->AcceptChanges(*createdIdCollection, *removedIdCollection);
if (!createdIdCollection->IsEmpty() || !removedIdCollection->IsEmpty() ||
!marksRenderCollection->empty() || !linesRenderCollection->empty())
{

View file

@ -5,5 +5,6 @@
namespace df
{
using MarkID = uint32_t;
using MarkGroupID = size_t;
using IDCollection = std::vector<MarkID>;
} // namespace df

View file

@ -22,19 +22,4 @@ UserLineMark::UserLineMark()
{
}
UserMarksProvider::UserMarksProvider()
: m_pendingOnDelete(false)
{
}
bool UserMarksProvider::IsPendingOnDelete()
{
return m_pendingOnDelete;
}
void UserMarksProvider::DeleteLater()
{
ASSERT(m_pendingOnDelete == false, ());
m_pendingOnDelete = true;
}
} // namespace df

View file

@ -15,8 +15,6 @@
namespace df
{
using MarkGroupID = size_t;
struct MarkIDCollection
{
IDCollection m_marksID;
@ -101,27 +99,13 @@ private:
class UserMarksProvider
{
public:
UserMarksProvider();
virtual ~UserMarksProvider() {}
virtual bool IsDirty() const = 0;
virtual void AcceptChanges(MarkIDCollection & createdMarks, MarkIDCollection & removedMarks) = 0;
virtual bool IsDrawable() const = 0;
virtual size_t GetUserPointCount() const = 0;
virtual void AcceptChanges(MarkGroupID groupID,
MarkIDCollection & updatedMarks, MarkIDCollection & createdMarks, MarkIDCollection & removedMarks) = 0;
/// never store UserPointMark reference
virtual UserPointMark const * GetUserPointMark(size_t index) const = 0;
virtual size_t GetUserLineCount() const = 0;
/// never store UserLineMark reference
virtual UserLineMark const * GetUserLineMark(size_t index) const = 0;
bool IsPendingOnDelete();
void DeleteLater();
private:
bool m_pendingOnDelete;
virtual UserPointMark const * GetUserPointMark(MarkID markID) const = 0;
/// never store UserLineMark reference
virtual UserLineMark const * GetUserLineMark(MarkID markID) const = 0;
};
} // namespace df

View file

@ -1,9 +1,11 @@
#import "MWMTableViewController.h"
#include "drape_frontend/user_marks_global.hpp"
@class AddSetVC;
@protocol AddSetVCDelegate <NSObject>
- (void)addSetVC:(AddSetVC *)vc didAddSetWithCategoryId:(int)categoryId;
- (void)addSetVC:(AddSetVC *)vc didAddSetWithCategoryId:(df::MarkGroupID)categoryId;
@end

View file

@ -37,7 +37,7 @@
if (text.length == 0)
return;
[self.delegate addSetVC:self
didAddSetWithCategoryId:static_cast<int>(GetFramework().AddCategory(text.UTF8String))];
didAddSetWithCategoryId:(GetFramework().AddCategory(text.UTF8String))];
[self.navigationController popViewControllerAnimated:YES];
}

View file

@ -52,7 +52,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
}
else
{
bool const showDetailedHint = GetFramework().GetBookmarkManager().GetBmCategoriesIds().empty();
bool const showDetailedHint = GetFramework().GetBookmarkManager().GetBmGroupsIdList().empty();
label.text =
showDetailedHint ? L(@"bookmarks_usage_hint") : L(@"bookmarks_usage_hint_import_only");
}
@ -118,7 +118,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
auto sz = GetFramework().GetBookmarkManager().GetBmCategoriesIds().size();
auto sz = GetFramework().GetBookmarkManager().GetBmGroupsIdList().size();
return sz;
}
@ -126,7 +126,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
{
NSInteger row = ((UITapGestureRecognizer *)sender).view.tag;
auto & bmManager = GetFramework().GetBookmarkManager();
auto categoryId = bmManager.GetBmCategoriesIds()[row];
auto categoryId = bmManager.GetBmGroupsIdList()[row];
UITableViewCell * cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:row inSection:0]];
if (cell && bmManager.HasBmCategory(categoryId))
{
@ -159,7 +159,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
cell.imageView.tag = indexPath.row;
auto & bmManager = GetFramework().GetBookmarkManager();
size_t const categoryIndex = bmManager.GetBmCategoriesIds()[indexPath.row];
size_t const categoryIndex = bmManager.GetBmGroupsIdList()[indexPath.row];
if (bmManager.HasBmCategory(categoryIndex))
{
NSString * title = @(bmManager.GetCategoryName(categoryIndex).c_str());
@ -168,7 +168,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
cell.imageView.image = [UIImage imageNamed:(isVisible ? @"ic_show" : @"ic_hide")];
cell.imageView.mwm_coloring = isVisible ? MWMImageColoringBlue : MWMImageColoringBlack;
cell.detailTextLabel.text = [NSString stringWithFormat:@"%ld",
bmManager.GetUserMarkCount(categoryIndex) + bmManager.GetTracksCount(categoryIndex)];
bmManager.GetUserMarkIds(categoryIndex).size() + bmManager.GetTrackIds(categoryIndex).size()];
}
cell.backgroundColor = [UIColor white];
cell.textLabel.textColor = [UIColor blackPrimaryText];
@ -219,7 +219,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
cell.textLabel.text = txt;
// Rename category
auto & bmManager = GetFramework().GetBookmarkManager();
size_t const categoryId = bmManager.GetBmCategoriesIds()[[self.tableView indexPathForCell:cell].row];
size_t const categoryId = bmManager.GetBmGroupsIdList()[[self.tableView indexPathForCell:cell].row];
if (bmManager.HasBmCategory(categoryId))
{
bmManager.SetCategoryName(categoryId, txt.UTF8String);
@ -268,7 +268,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
}
else
{
auto categoryId = GetFramework().GetBookmarkManager().GetBmCategoriesIds()[indexPath.row];
auto categoryId = GetFramework().GetBookmarkManager().GetBmGroupsIdList()[indexPath.row];
BookmarksVC * bvc = [[BookmarksVC alloc] initWithCategory:categoryId];
[self.navigationController pushViewController:bvc animated:YES];
}
@ -290,7 +290,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
f.DeleteBmCategory(indexPath.row);
[self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
// Disable edit mode if no categories are left
if (f.GetBookmarkManager().GetBmCategoriesIds().empty())
if (f.GetBookmarkManager().GetBmGroupsIdList().empty())
{
self.navigationItem.rightBarButtonItem = nil;
[self setEditing:NO animated:YES];
@ -302,7 +302,7 @@ extern NSString * const kBookmarkCategoryDeletedNotification =
{
[super viewWillAppear:animated];
// Display Edit button only if table is not empty
if (!GetFramework().GetBookmarkManager().GetBmCategoriesIds().empty())
if (!GetFramework().GetBookmarkManager().GetBmGroupsIdList().empty())
self.navigationItem.rightBarButtonItem = self.editButtonItem;
else
self.navigationItem.rightBarButtonItem = nil;

View file

@ -1,10 +1,14 @@
#import "MWMTableViewController.h"
#include "drape_frontend/user_marks_global.hpp"
@interface BookmarksVC : MWMTableViewController <UITextFieldDelegate>
{
NSUInteger m_categoryId;
df::MarkGroupID m_categoryId;
NSMutableArray * m_bookmarkIds;
NSMutableArray * m_trackIds;
}
- (instancetype)initWithCategory:(NSUInteger)index;
- (instancetype)initWithCategory:(df::MarkGroupID)index;
@end

View file

@ -33,13 +33,23 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
@implementation BookmarksVC
- (instancetype)initWithCategory:(NSUInteger)index
- (instancetype)initWithCategory:(df::MarkGroupID)index
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
{
m_categoryId = index;
self.title = @(GetFramework().GetBookmarkManager().GetCategoryName(index).c_str());
auto const & bmManager = GetFramework().GetBookmarkManager();
self.title = @(bmManager.GetCategoryName(m_categoryId).c_str());
auto const & bookmarkIds = bmManager.GetUserMarkIds(m_categoryId);
auto const & trackIds = bmManager.GetTrackIds(m_categoryId);
// TODO(darina): should we release these arrays manually?
m_bookmarkIds = [NSMutableArray arrayWithCapacity:bookmarkIds.size()];
m_trackIds = [NSMutableArray arrayWithCapacity:trackIds.size()];
for (auto bookmarkId : bookmarkIds)
[m_bookmarkIds addObject:[NSNumber numberWithInt:bookmarkId]];
for (auto trackId : trackIds)
[m_trackIds addObject:[NSNumber numberWithInt:trackId]];
[self calculateSections];
}
return self;
@ -61,9 +71,9 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
if (section == 0)
return 2;
else if (section == m_trackSection)
return GetFramework().GetBookmarkManager().GetTracksCount(m_categoryId);
return GetFramework().GetBookmarkManager().GetTrackIds(m_categoryId).size();
else if (section == m_bookmarkSection)
return GetFramework().GetBookmarkManager().GetUserMarkCount(m_categoryId);
return GetFramework().GetBookmarkManager().GetUserMarkIds(m_categoryId).size();
else if (section == m_shareSection)
return 1;
else
@ -129,7 +139,8 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
cell = [tableView dequeueReusableCellWithIdentifier:@"TrackCell"];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"TrackCell"];
Track const * tr = bmManager.GetTrack(m_categoryId, indexPath.row);
df::MarkID trackId = [[m_trackIds objectAtIndex:indexPath.row] intValue];
Track const * tr = bmManager.GetTrack(trackId);
cell.textLabel.text = @(tr->GetName().c_str());
string dist;
if (measurement_utils::FormatDistance(tr->GetLengthMeters(), dist))
@ -147,7 +158,8 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
UITableViewCell * bmCell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"BookmarksVCBookmarkItemCell"];
if (!bmCell)
bmCell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"BookmarksVCBookmarkItemCell"];
Bookmark const * bm = bmManager.GetBookmark(m_categoryId, indexPath.row);
df::MarkID bmId = [[m_bookmarkIds objectAtIndex:indexPath.row] intValue];
Bookmark const * bm = bmManager.GetBookmark(bmId);
if (bm)
{
bmCell.textLabel.text = @(bm->GetName().c_str());
@ -210,7 +222,8 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
{
if (categoryExists)
{
Track const * tr = bmManager.GetTrack(m_categoryId, indexPath.row);
df::MarkID trackId = [[m_trackIds objectAtIndex:indexPath.row] intValue];
Track const * tr = bmManager.GetTrack(trackId);
ASSERT(tr, ("NULL track"));
if (tr)
{
@ -223,14 +236,15 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
{
if (categoryExists)
{
Bookmark const * bm = bmManager.GetBookmark(m_categoryId, indexPath.row);
df::MarkID bmId = [[m_bookmarkIds objectAtIndex:indexPath.row] intValue];
Bookmark const * bm = bmManager.GetBookmark(bmId);
ASSERT(bm, ("NULL bookmark"));
if (bm)
{
[Statistics logEvent:kStatEventName(kStatBookmarks, kStatShowOnMap)];
// Same as "Close".
[MWMSearchManager manager].state = MWMSearchManagerStateHidden;
f.ShowBookmark({static_cast<size_t>(indexPath.row), m_categoryId});
f.ShowBookmark(bm);
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
@ -283,15 +297,18 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
{
if (indexPath.section == m_trackSection)
{
bmManager.DeleteTrack(m_categoryId, indexPath.row);
df::MarkID trackId = [[m_trackIds objectAtIndex:indexPath.row] intValue];
bmManager.DeleteTrack(trackId);
[m_trackIds removeObjectAtIndex:indexPath.row];
}
else
{
auto bac = BookmarkAndCategory(static_cast<size_t>(indexPath.row), m_categoryId);
NSValue * value = [NSValue valueWithBytes:&bac objCType:@encode(BookmarkAndCategory)];
df::MarkID bmId = [[m_bookmarkIds objectAtIndex:indexPath.row] intValue];
NSValue * value = [NSValue valueWithBytes:&bmId objCType:@encode(df::MarkID*)];
[NSNotificationCenter.defaultCenter postNotificationName:kBookmarkDeletedNotification
object:value];
bmManager.DeleteUserMark(m_categoryId, indexPath.row);
bmManager.DeleteUserMark(bmId);
[m_bookmarkIds removeObjectAtIndex:indexPath.row];
[NSNotificationCenter.defaultCenter postNotificationName:kBookmarksChangedNotification
object:nil
userInfo:nil];
@ -306,7 +323,7 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
[self.tableView deleteRowsAtIndexPaths:@[ indexPath ] withRowAnimation:UITableViewRowAnimationFade];
else
[self.tableView reloadData];
if (bmManager.GetUserMarkCount(m_categoryId) + bmManager.GetTracksCount(m_categoryId) == 0)
if (bmManager.GetUserMarkIds(m_categoryId).size() + bmManager.GetTrackIds(m_categoryId).size() == 0)
{
self.navigationItem.rightBarButtonItem = nil;
[self setEditing:NO animated:YES];
@ -329,7 +346,8 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
NSIndexPath * indexPath = [table indexPathForCell:cell];
if (indexPath.section == self->m_bookmarkSection)
{
Bookmark const * bm = bmManager.GetBookmark(m_categoryId, indexPath.row);
df::MarkID bmId = [[m_bookmarkIds objectAtIndex:indexPath.row] intValue];
Bookmark const * bm = bmManager.GetBookmark(bmId);
if (bm)
{
m2::PointD const center = bm->GetPivot();
@ -352,7 +370,7 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
// Display Edit button only if table is not empty
auto & bmManager = GetFramework().GetBookmarkManager();
if (bmManager.HasBmCategory(m_categoryId)
&& (bmManager.GetUserMarkCount(m_categoryId) + bmManager.GetTracksCount(m_categoryId)))
&& (bmManager.GetUserMarkIds(m_categoryId).size() + bmManager.GetTrackIds(m_categoryId).size()))
self.navigationItem.rightBarButtonItem = self.editButtonItem;
else
self.navigationItem.rightBarButtonItem = nil;
@ -444,11 +462,11 @@ extern NSString * const kBookmarkDeletedNotification = @"BookmarkDeletedNotifica
{
int index = 1;
auto & bmManager = GetFramework().GetBookmarkManager();
if (bmManager.GetTracksCount(m_categoryId))
if (bmManager.GetTrackIds(m_categoryId).size())
m_trackSection = index++;
else
m_trackSection = EMPTY_SECTION;
if (bmManager.GetUserMarkCount(m_categoryId))
if (bmManager.GetUserMarkIds(m_categoryId).size())
m_bookmarkSection = index++;
else
m_bookmarkSection = EMPTY_SECTION;

View file

@ -1,17 +1,17 @@
#import "MWMTableViewController.h"
struct BookmarkAndCategory;
#include "drape_frontend/user_marks_global.hpp"
@protocol MWMSelectSetDelegate <NSObject>
- (void)didSelectCategory:(NSString *)category withCategoryIndex:(size_t)categoryIndex;
- (void)didSelectCategory:(NSString *)category withCategoryId:(df::MarkGroupID)categoryId;
@end
@interface SelectSetVC : MWMTableViewController
- (instancetype)initWithCategory:(NSString *)category
categoryIndex:(size_t)categoryIndex
categoryId:(df::MarkGroupID)categoryId
delegate:(id<MWMSelectSetDelegate>)delegate;
@end

View file

@ -7,7 +7,7 @@
@interface SelectSetVC () <AddSetVCDelegate>
{
size_t m_categoryIndex;
df::MarkGroupID m_categoryId;
}
@property (copy, nonatomic) NSString * category;
@ -18,14 +18,14 @@
@implementation SelectSetVC
- (instancetype)initWithCategory:(NSString *)category
categoryIndex:(size_t)categoryIndex
categoryId:(df::MarkGroupID)categoryId
delegate:(id<MWMSelectSetDelegate>)delegate
{
self = [super initWithStyle:UITableViewStyleGrouped];
if (self)
{
_category = category;
m_categoryIndex = categoryIndex;
m_categoryId = categoryId;
_delegate = delegate;
}
return self;
@ -50,7 +50,7 @@
if (section == 0)
return 1;
return GetFramework().GetBookmarkManager().GetBmCategoriesIds().size();
return GetFramework().GetBookmarkManager().GetBmGroupsIdList().size();
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
@ -65,11 +65,11 @@
else
{
auto & bmManager = GetFramework().GetBookmarkManager();
auto categoryId = bmManager.GetBmCategoriesIds()[indexPath.row];
auto categoryId = bmManager.GetBmGroupsIdList()[indexPath.row];
if (bmManager.HasBmCategory(categoryId))
cell.textLabel.text = @(bmManager.GetCategoryName(categoryId).c_str());
if (m_categoryIndex == categoryId)
if (m_categoryId == categoryId)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
@ -77,14 +77,14 @@
return cell;
}
- (void)addSetVC:(AddSetVC *)vc didAddSetWithCategoryId:(int)categoryId
- (void)addSetVC:(AddSetVC *)vc didAddSetWithCategoryId:(df::MarkGroupID)categoryId
{
[self moveBookmarkToSetWithCategoryId:categoryId];
[self.tableView reloadData];
[self.delegate didSelectCategory:self.category withCategoryIndex:categoryId];
[self.delegate didSelectCategory:self.category withCategoryId:categoryId];
}
- (void)moveBookmarkToSetWithCategoryId:(int)categoryId
- (void)moveBookmarkToSetWithCategoryId:(df::MarkGroupID)categoryId
{
self.category = @(GetFramework().GetBookmarkManager().GetCategoryName(categoryId).c_str());
}
@ -100,9 +100,9 @@
}
else
{
auto categoryId = GetFramework().GetBookmarkManager().GetBmCategoriesIds()[indexPath.row];
[self moveBookmarkToSetWithCategoryId:static_cast<int>(categoryId)];
[self.delegate didSelectCategory:self.category withCategoryIndex:categoryId];
auto categoryId = GetFramework().GetBookmarkManager().GetBmGroupsIdList()[indexPath.row];
[self moveBookmarkToSetWithCategoryId:categoryId];
[self.delegate didSelectCategory:self.category withCategoryId:categoryId];
[self backTap];
}
}

View file

@ -365,7 +365,7 @@ BOOL gIsFirstMyPositionMode = YES;
- (void)openMigration { [self performSegueWithIdentifier:kMigrationSegue sender:self]; }
- (void)openBookmarks
{
auto const & ids = GetFramework().GetBookmarkManager().GetBmCategoriesIds();
auto const & ids = GetFramework().GetBookmarkManager().GetBmGroupsIdList();
BOOL const oneCategory = (ids.size() == 1);
MWMTableViewController * vc =
oneCategory ? [[BookmarksVC alloc] initWithCategory:(ids.front())] : [[BookmarksRootVC alloc] init];

View file

@ -29,13 +29,14 @@ enum RowInMetaInfo
RowsInMetaInfoCount
};
static int const kInvalidCategoryIndex = -1;
static int const kInvalidCategoryId = 0;
} // namespace
@interface MWMEditBookmarkController () <MWMButtonCellDelegate, MWMNoteCelLDelegate, MWMBookmarkColorDelegate,
MWMSelectSetDelegate, MWMBookmarkTitleDelegate>
{
BookmarkAndCategory m_cachedBookmarkAndCategory;
df::MarkID m_cachedBookmarkId;
df::MarkGroupID m_cachedBookmarkCatId;
}
@property (nonatomic) MWMNoteCell * cachedNote;
@ -43,7 +44,7 @@ static int const kInvalidCategoryIndex = -1;
@property (copy, nonatomic) NSString * cachedTitle;
@property (copy, nonatomic) NSString * cachedColor;
@property (copy, nonatomic) NSString * cachedCategory;
@property(nonatomic) int64_t cachedCategoryIndex;
@property(nonatomic) df::MarkGroupID cachedBmCatId;
@end
@ -52,14 +53,15 @@ static int const kInvalidCategoryIndex = -1;
- (void)viewDidLoad
{
[super viewDidLoad];
self.cachedCategoryIndex = kInvalidCategoryIndex;
self.cachedBmCatId = kInvalidCategoryId;
auto data = self.data;
NSAssert(data, @"Data can't be nil!");
self.cachedDescription = data.bookmarkDescription;
self.cachedTitle = data.title;
self.cachedCategory = data.bookmarkCategory;
self.cachedColor = data.bookmarkColor;
m_cachedBookmarkAndCategory = data.bookmarkAndCategory;
m_cachedBookmarkId = data.bookmarkId;
m_cachedBookmarkCatId = data.bookmarkCategoryId;
[self configNavBar];
[self registerCells];
}
@ -92,19 +94,14 @@ static int const kInvalidCategoryIndex = -1;
{
[self.view endEditing:YES];
auto & f = GetFramework();
if (self.cachedCategoryIndex != kInvalidCategoryIndex)
if (self.cachedBmCatId != kInvalidCategoryId)
{
auto const index = static_cast<size_t>(
f.MoveBookmark(m_cachedBookmarkAndCategory.m_bookmarkIndex,
m_cachedBookmarkAndCategory.m_categoryIndex,
self.cachedCategoryIndex));
m_cachedBookmarkAndCategory.m_bookmarkIndex = index;
m_cachedBookmarkAndCategory.m_categoryIndex = self.cachedCategoryIndex;
f.MoveBookmark(m_cachedBookmarkId, m_cachedBookmarkCatId, self.cachedBmCatId);
m_cachedBookmarkCatId = self.cachedBmCatId;
}
BookmarkManager & bmManager = f.GetBookmarkManager();
auto bookmark = bmManager.GetBookmarkForEdit(m_cachedBookmarkAndCategory.m_categoryIndex,
m_cachedBookmarkAndCategory.m_bookmarkIndex);
auto bookmark = bmManager.GetBookmarkForEdit(m_cachedBookmarkId);
if (!bookmark)
return;
@ -112,8 +109,8 @@ static int const kInvalidCategoryIndex = -1;
bookmark->SetDescription(self.cachedDescription.UTF8String);
bookmark->SetName(self.cachedTitle.UTF8String);
bmManager.SaveToKMLFile(m_cachedBookmarkAndCategory.m_categoryIndex);
bmManager.NotifyChanges(m_cachedBookmarkAndCategory.m_categoryIndex);
bmManager.SaveToKMLFile(m_cachedBookmarkCatId);
bmManager.NotifyChanges(m_cachedBookmarkCatId);
f.UpdatePlacePageInfoForCurrentSelection();
[self backTap];
@ -237,7 +234,7 @@ static int const kInvalidCategoryIndex = -1;
case Category:
{
SelectSetVC * svc = [[SelectSetVC alloc] initWithCategory:self.cachedCategory
categoryIndex:m_cachedBookmarkAndCategory.m_categoryIndex
categoryId:m_cachedBookmarkCatId
delegate:self];
[self.navigationController pushViewController:svc animated:YES];
break;
@ -283,10 +280,10 @@ static int const kInvalidCategoryIndex = -1;
#pragma mark - MWMSelectSetDelegate
- (void)didSelectCategory:(NSString *)category withCategoryIndex:(size_t)categoryIndex
- (void)didSelectCategory:(NSString *)category withCategoryId:(df::MarkGroupID)categoryId
{
self.cachedCategory = category;
self.cachedCategoryIndex = categoryIndex;
self.cachedBmCatId = categoryId;
[self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:Category inSection:MetaInfo]] withRowAnimation:UITableViewRowAnimationAutomatic];
}

View file

@ -13,7 +13,6 @@
@class MWMPlacePageData;
@class MWMUGCReviewVM;
struct BookmarkAndCategory;
struct FeatureID;
namespace ugc
@ -216,7 +215,8 @@ using NewSectionsAreReady = void (^)(NSRange const & range, MWMPlacePageData * d
- (NSString *)bookmarkColor;
- (NSString *)bookmarkDescription;
- (NSString *)bookmarkCategory;
- (BookmarkAndCategory)bookmarkAndCategory;
- (df::MarkID)bookmarkId;
- (df::MarkGroupID)bookmarkCategoryId;
// Local Ads
- (NSString *)localAdsURL;

View file

@ -432,26 +432,24 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS";
auto & bmManager = f.GetBookmarkManager();
if (isBookmark)
{
auto const categoryIndex = f.LastEditedBMCategory();
auto const categoryId = f.LastEditedBMCategory();
BookmarkData bmData{m_info.FormatNewBookmarkName(), f.LastEditedBMType()};
auto const bookmarkIndex = bmManager.AddBookmark(categoryIndex, self.mercator, bmData);
auto const * bookmark = bmManager.GetBookmark(categoryIndex, bookmarkIndex);
f.FillBookmarkInfo(*bookmark, {bookmarkIndex, categoryIndex}, m_info);
bmManager.NotifyChanges(categoryIndex);
auto const * bookmark = bmManager.CreateBookmark(self.mercator, bmData, categoryId);
f.FillBookmarkInfo(*bookmark, m_info);
bmManager.NotifyChanges(categoryId);
m_sections.insert(m_sections.begin() + 1, Sections::Bookmark);
}
else
{
auto const bac = m_info.GetBookmarkAndCategory();
auto const * bookmark = bmManager.GetBookmark(bac.m_categoryIndex, bac.m_bookmarkIndex);
auto const bookmarkId = m_info.GetBookmarkId();
auto const * bookmark = bmManager.GetBookmark(bookmarkId);
if (bookmark)
{
f.ResetBookmarkInfo(*bookmark, m_info);
bmManager.DeleteUserMark(bac.m_categoryIndex, bac.m_bookmarkIndex);
bmManager.NotifyChanges(bac.m_categoryIndex);
bmManager.SaveToKMLFile(bac.m_categoryIndex);
auto const categoryId = bookmark->GetGroupId();
bmManager.DeleteBookmark(bookmarkId);
bmManager.NotifyChanges(categoryId);
bmManager.SaveToKMLFile(categoryId);
}
m_sections.erase(remove(m_sections.begin(), m_sections.end(), Sections::Bookmark));
@ -695,9 +693,14 @@ NSString * const kUserDefaultsLatLonAsDMSKey = @"UserDefaultsLatLonAsDMS";
return m_info.IsBookmark() ? @(m_info.GetBookmarkCategoryName().c_str()) : nil;
}
- (BookmarkAndCategory)bookmarkAndCategory
- (df::MarkID)bookmarkId
{
return m_info.IsBookmark() ? m_info.GetBookmarkAndCategory() : BookmarkAndCategory();
return m_info.IsBookmark() ? m_info.GetBookmarkId() : 0;
}
- (df::MarkGroupID)bookmarkCategoryId
{
return m_info.IsBookmark() ? m_info.GetBookmarkCategoryId() : 0;
}
#pragma mark - Local Ads

View file

@ -128,13 +128,10 @@ void logSponsoredEvent(MWMPlacePageData * data, NSString * eventName)
return;
auto value = static_cast<NSValue *>(notification.object);
auto deletedBookmarkAndCategory = BookmarkAndCategory();
[value getValue:&deletedBookmarkAndCategory];
NSAssert(deletedBookmarkAndCategory.IsValid(),
@"Place page must have valid bookmark and category.");
auto bookmarkAndCategory = data.bookmarkAndCategory;
if (bookmarkAndCategory.m_bookmarkIndex != deletedBookmarkAndCategory.m_bookmarkIndex ||
bookmarkAndCategory.m_categoryIndex != deletedBookmarkAndCategory.m_categoryIndex)
df::MarkID deletedBookmarkId = 0;
[value getValue:&deletedBookmarkId];
auto bookmarkId = data.bookmarkId;
if (bookmarkId != deletedBookmarkId)
return;
[self closePlacePage];
@ -147,9 +144,9 @@ void logSponsoredEvent(MWMPlacePageData * data, NSString * eventName)
if (!data.isBookmark)
return;
auto deletedIndex = static_cast<NSNumber *>(notification.object).integerValue;
auto index = data.bookmarkAndCategory.m_categoryIndex;
if (index != deletedIndex)
auto deletedCategoryId = static_cast<NSNumber *>(notification.object).integerValue;
auto categoryId = data.bookmarkCategoryId;
if (categoryId != deletedCategoryId)
return;
[self closePlacePage];

View file

@ -8,9 +8,9 @@
#include "geometry/mercator.hpp"
#include "coding/file_reader.hpp"
#include "coding/hex.hpp"
#include "coding/parse_xml.hpp" // LoadFromKML
#include "coding/internal/file_data.hpp"
#include "coding/hex.hpp"
#include "drape/drape_global.hpp"
#include "drape/color.hpp"
@ -28,15 +28,15 @@
#include <map>
#include <memory>
Bookmark::Bookmark(m2::PointD const & ptOrg, size_t categoryId)
Bookmark::Bookmark(m2::PointD const & ptOrg)
: Base(ptOrg, UserMark::BOOKMARK)
, m_categoryId(categoryId)
, m_groupId(0)
{}
Bookmark::Bookmark(BookmarkData const & data, m2::PointD const & ptOrg, size_t categoryId)
Bookmark::Bookmark(BookmarkData const & data, m2::PointD const & ptOrg)
: Base(ptOrg, UserMark::BOOKMARK)
, m_data(data)
, m_categoryId(categoryId)
, m_groupId(0)
{}
void Bookmark::SetData(BookmarkData const & data)
@ -125,23 +125,28 @@ void Bookmark::SetScale(double scale)
m_data.SetScale(scale);
}
void BookmarkCategory::AddTrack(std::unique_ptr<Track> && track)
df::MarkGroupID Bookmark::GetGroupId() const
{
SetDirty();
m_tracks.push_back(move(track));
return m_groupId;
}
Track const * BookmarkCategory::GetTrack(size_t index) const
void Bookmark::Attach(df::MarkGroupID groupID)
{
return (index < m_tracks.size() ? m_tracks[index].get() : 0);
ASSERT(!m_groupId, ());
m_groupId = groupID;
}
void Bookmark::Detach()
{
m_groupId = 0;
}
BookmarkCategory::BookmarkCategory(std::string const & name,
size_t index,
df::MarkGroupID groupID,
Listeners const & listeners)
: Base(UserMark::Type::BOOKMARK, listeners)
, m_groupID(groupID)
, m_name(name)
, m_index(index)
{}
BookmarkCategory::~BookmarkCategory()
@ -154,36 +159,32 @@ size_t BookmarkCategory::GetUserLineCount() const
return m_tracks.size();
}
df::UserLineMark const * BookmarkCategory::GetUserLineMark(size_t index) const
{
ASSERT_LESS(index, m_tracks.size(), ());
return m_tracks[index].get();
}
void BookmarkCategory::ClearTracks()
{
SetDirty();
m_tracks.clear();
}
void BookmarkCategory::DeleteTrack(size_t index)
void BookmarkCategory::AcceptChanges(df::MarkIDCollection & groupMarks,
df::MarkIDCollection & createdMarks,
df::MarkIDCollection & removedMarks)
{
SetDirty();
ASSERT_LESS(index, m_tracks.size(), ());
m_tracks.erase(next(m_tracks.begin(), index));
Base::AcceptChanges(groupMarks, createdMarks, removedMarks);
groupMarks.m_linesID.reserve(m_tracks.size());
for(auto const & trackID : m_tracks)
groupMarks.m_linesID.push_back(trackID);
}
std::vector<std::unique_ptr<Track>> BookmarkCategory::StealTracks()
{
std::vector<std::unique_ptr<Track>> tracks;
std::swap(m_tracks, tracks);
return tracks;
}
void BookmarkCategory::AppendTracks(std::vector<std::unique_ptr<Track>> && tracks)
void BookmarkCategory::AttachTrack(df::MarkID trackId)
{
SetDirty();
std::move(tracks.begin(), tracks.end(), std::back_inserter(m_tracks));
m_tracks.insert(trackId);
}
void BookmarkCategory::DetachTrack(df::MarkID trackId)
{
SetDirty();
m_userMarks.erase(trackId);
}
namespace
@ -229,7 +230,7 @@ class KMLParser
return style::GetSupportedStyle(result, m_name, style::GetDefaultStyle());
}
BookmarkCategory & m_category;
KMLData & m_data;
std::vector<std::string> m_tags;
GeometryType m_geometryType;
@ -368,8 +369,8 @@ class KMLParser
}
public:
KMLParser(BookmarkCategory & cat)
: m_category(cat)
KMLParser(KMLData & data)
: m_data(data)
{
Reset();
}
@ -417,17 +418,16 @@ public:
{
if (GEOMETRY_TYPE_POINT == m_geometryType)
{
Bookmark * bm = static_cast<Bookmark *>(m_category.CreateUserMark(m_org));
bm->SetData(BookmarkData(m_name, m_type, m_description, m_scale, m_timeStamp));
m_data.m_bookmarks.emplace_back(std::make_unique<Bookmark>(
BookmarkData(m_name, m_type, m_description, m_scale, m_timeStamp), m_org));
}
else if (GEOMETRY_TYPE_LINE == m_geometryType)
{
Track::Params params;
params.m_colors.push_back({ kDefaultTrackWidth, m_trackColor });
params.m_name = m_name;
/// @todo Add description, style, timestamp
m_category.AddTrack(make_unique<Track>(m_points, params));
m_data.m_tracks.emplace_back(std::make_unique<Track>(m_points, params));
}
}
Reset();
@ -461,9 +461,9 @@ public:
if (prevTag == kDocument)
{
if (currTag == "name")
m_category.SetName(value);
m_data.m_name = value;
else if (currTag == "visibility")
m_category.SetIsVisible(value == "0" ? false : true);
m_data.m_visible = value == "0" ? false : true;
}
else if (prevTag == kPlacemark)
{
@ -574,295 +574,24 @@ std::string BookmarkCategory::GetDefaultType()
return style::GetDefaultStyle();
}
bool BookmarkCategory::LoadFromKML(ReaderPtr<Reader> const & reader)
std::unique_ptr<KMLData> LoadKMLFile(std::string const & file)
{
ReaderSource<ReaderPtr<Reader> > src(reader);
KMLParser parser(*this);
if (!ParseXML(src, parser, true))
{
LOG(LWARNING, ("XML read error. Probably, incorrect file encoding."));
return false;
}
return true;
}
// static
std::unique_ptr<BookmarkCategory> BookmarkCategory::CreateFromKMLFile(std::string const & file,
size_t index,
Listeners const & listeners)
{
auto cat = my::make_unique<BookmarkCategory>("", index, listeners);
auto data = std::make_unique<KMLData>();
data->m_file = file;
try
{
if (cat->LoadFromKML(my::make_unique<FileReader>(file)))
cat->m_file = file;
else
cat.reset();
ReaderSource<ReaderPtr<Reader> > src(std::make_unique<FileReader>(file));
KMLParser parser(*data);
if (!ParseXML(src, parser, true))
{
LOG(LWARNING, ("XML read error. Probably, incorrect file encoding."));
data.reset();
}
}
catch (std::exception const & e)
{
LOG(LWARNING, ("Error while loading bookmarks from", file, e.what()));
cat.reset();
data.reset();
}
return cat;
}
namespace
{
char const * kmlHeader =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<kml xmlns=\"http://earth.google.com/kml/2.2\">\n"
"<Document>\n"
" <Style id=\"placemark-blue\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-blue.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
" <Style id=\"placemark-brown\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-brown.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
" <Style id=\"placemark-green\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-green.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
" <Style id=\"placemark-orange\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-orange.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
" <Style id=\"placemark-pink\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-pink.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
" <Style id=\"placemark-purple\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-purple.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
" <Style id=\"placemark-red\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-red.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
" <Style id=\"placemark-yellow\">\n"
" <IconStyle>\n"
" <Icon>\n"
" <href>http://mapswith.me/placemarks/placemark-yellow.png</href>\n"
" </Icon>\n"
" </IconStyle>\n"
" </Style>\n"
;
char const * kmlFooter =
"</Document>\n"
"</kml>\n";
}
namespace
{
inline void SaveStringWithCDATA(std::ostream & stream, std::string const & s)
{
// According to kml/xml spec, we need to escape special symbols with CDATA
if (s.find_first_of("<&") != std::string::npos)
stream << "<![CDATA[" << s << "]]>";
else
stream << s;
}
}
void BookmarkCategory::SaveToKML(std::ostream & s)
{
s << kmlHeader;
// Use CDATA if we have special symbols in the name
s << " <name>";
SaveStringWithCDATA(s, GetName());
s << "</name>\n";
s << " <visibility>" << (IsVisible() ? "1" : "0") <<"</visibility>\n";
// Bookmarks are stored to KML file in reverse order, so, least
// recently added bookmark will be stored last. The reason is that
// when bookmarks will be loaded from the KML file, most recently
// added bookmark will be loaded last and in accordance with current
// logic will added to the beginning of the bookmarks list. Thus,
// this method preserves LRU bookmarks order after store -> load
// actions.
//
// Loop invariant: on each iteration count means number of already
// stored bookmarks and i means index of the bookmark that should be
// processed during the iteration. That's why i is initially set to
// GetBookmarksCount() - 1, i.e. to the last bookmark in the
// bookmarks list.
for (size_t count = 0, i = GetUserMarkCount() - 1;
count < GetUserPointCount(); ++count, --i)
{
Bookmark const * bm = static_cast<Bookmark const *>(GetUserMark(i));
s << " <Placemark>\n";
s << " <name>";
SaveStringWithCDATA(s, bm->GetName());
s << "</name>\n";
if (!bm->GetDescription().empty())
{
s << " <description>";
SaveStringWithCDATA(s, bm->GetDescription());
s << "</description>\n";
}
time_t const timeStamp = bm->GetTimeStamp();
if (timeStamp != my::INVALID_TIME_STAMP)
{
std::string const strTimeStamp = my::TimestampToString(timeStamp);
ASSERT_EQUAL(strTimeStamp.size(), 20, ("We always generate fixed length UTC-format timestamp"));
s << " <TimeStamp><when>" << strTimeStamp << "</when></TimeStamp>\n";
}
s << " <styleUrl>#" << bm->GetType() << "</styleUrl>\n"
<< " <Point><coordinates>" << PointToString(bm->GetPivot()) << "</coordinates></Point>\n";
double const scale = bm->GetScale();
if (scale != -1.0)
{
/// @todo Factor out to separate function to use for other custom params.
s << " <ExtendedData xmlns:mwm=\"http://mapswith.me\">\n"
<< " <mwm:scale>" << bm->GetScale() << "</mwm:scale>\n"
<< " </ExtendedData>\n";
}
s << " </Placemark>\n";
}
// Saving tracks
for (size_t i = 0; i < GetTracksCount(); ++i)
{
Track const * track = GetTrack(i);
s << " <Placemark>\n";
s << " <name>";
SaveStringWithCDATA(s, track->GetName());
s << "</name>\n";
ASSERT_GREATER(track->GetLayerCount(), 0, ());
s << "<Style><LineStyle>";
dp::Color const & col = track->GetColor(0);
s << "<color>"
<< NumToHex(col.GetAlpha())
<< NumToHex(col.GetBlue())
<< NumToHex(col.GetGreen())
<< NumToHex(col.GetRed());
s << "</color>\n";
s << "<width>"
<< track->GetWidth(0);
s << "</width>\n";
s << "</LineStyle></Style>\n";
// stop style saving
s << " <LineString><coordinates>";
Track::PolylineD const & poly = track->GetPolyline();
for (auto pt = poly.Begin(); pt != poly.End(); ++pt)
s << PointToString(*pt) << " ";
s << " </coordinates></LineString>\n"
<< " </Placemark>\n";
}
s << kmlFooter;
}
UserMark * BookmarkCategory::AllocateUserMark(m2::PointD const & ptOrg)
{
return new Bookmark(ptOrg, m_index);
}
bool BookmarkCategory::SaveToKMLFile()
{
std::string oldFile;
// Get valid file name from category name
std::string const name = BookmarkManager::RemoveInvalidSymbols(m_name);
if (!m_file.empty())
{
size_t i2 = m_file.find_last_of('.');
if (i2 == std::string::npos)
i2 = m_file.size();
size_t i1 = m_file.find_last_of("\\/");
if (i1 == std::string::npos)
i1 = 0;
else
++i1;
// If m_file doesn't match name, assign new m_file for this category and save old file name.
if (m_file.substr(i1, i2 - i1).find(name) != 0)
{
oldFile = BookmarkManager::GenerateUniqueFileName(GetPlatform().SettingsDir(), name);
m_file.swap(oldFile);
}
}
else
{
m_file = BookmarkManager::GenerateUniqueFileName(GetPlatform().SettingsDir(), name);
}
std::string const fileTmp = m_file + ".tmp";
try
{
// First, we save to the temporary file
/// @todo On Windows UTF-8 file names are not supported.
std::ofstream of(fileTmp.c_str(), std::ios_base::out | std::ios_base::trunc);
SaveToKML(of);
of.flush();
if (!of.fail())
{
// Only after successfull save we replace original file
my::DeleteFileX(m_file);
VERIFY(my::RenameFileX(fileTmp, m_file), (fileTmp, m_file));
// delete old file
if (!oldFile.empty())
VERIFY(my::DeleteFileX(oldFile), (oldFile, m_file));
return true;
}
}
catch (std::exception const & e)
{
LOG(LWARNING, ("Exception while saving bookmarks:", e.what()));
}
LOG(LWARNING, ("Can't save bookmarks category", m_name, "to file", m_file));
// remove possibly left tmp file
my::DeleteFileX(fileTmp);
// return old file name in case of error
if (!oldFile.empty())
m_file.swap(oldFile);
return false;
return data;
}

View file

@ -74,9 +74,9 @@ class Bookmark : public UserMark
{
using Base = UserMark;
public:
Bookmark(m2::PointD const & ptOrg, size_t categoryId);
Bookmark(m2::PointD const & ptOrg);
Bookmark(BookmarkData const & data, m2::PointD const & ptOrg, size_t categoryId);
Bookmark(BookmarkData const & data, m2::PointD const & ptOrg);
void SetData(BookmarkData const & data);
BookmarkData const & GetData() const;
@ -102,11 +102,13 @@ public:
double GetScale() const;
void SetScale(double scale);
size_t GetCategoryId() const { return m_categoryId; }
df::MarkGroupID GetGroupId() const override;
void Attach(df::MarkGroupID groupId);
void Detach();
private:
BookmarkData m_data;
size_t m_categoryId;
df::MarkGroupID m_groupId;
};
class BookmarkCategory : public UserMarkContainer
@ -114,74 +116,47 @@ class BookmarkCategory : public UserMarkContainer
using Base = UserMarkContainer;
public:
BookmarkCategory(std::string const & name, size_t index, Listeners const & listeners);
BookmarkCategory(std::string const & name, df::MarkGroupID groupID, Listeners const & listeners);
~BookmarkCategory() override;
protected:
friend class BookmarkManager;
friend class KMLParser;
size_t GetUserLineCount() const override;
df::UserLineMark const * GetUserLineMark(size_t index) const override;
static std::string GetDefaultType();
void ClearTracks();
void AcceptChanges(df::MarkIDCollection & groupMarks,
df::MarkIDCollection & createdMarks,
df::MarkIDCollection & removedMarks) override;
void AddTrack(std::unique_ptr<Track> && track);
Track const * GetTrack(size_t index) const;
inline size_t GetTracksCount() const { return m_tracks.size(); }
void DeleteTrack(size_t index);
void AttachTrack(df::MarkID markId);
void DetachTrack(df::MarkID markId);
std::vector<std::unique_ptr<Track>> StealTracks();
void AppendTracks(std::vector<std::unique_ptr<Track>> && tracks);
df::MarkGroupID GetID() const { return m_groupID; }
MarkIDSet const & GetTracks() const { return m_tracks; }
void SetName(std::string const & name) { m_name = name; }
void SetFileName(std::string const & fileName) { m_file = fileName; }
std::string const & GetName() const { return m_name; }
std::string const & GetFileName() const { return m_file; }
/// @name Theese fuctions are public for unit tests only.
/// You don't need to call them from client code.
//@{
bool LoadFromKML(ReaderPtr<Reader> const & reader);
void SaveToKML(std::ostream & s);
/// Uses the same file name from which was loaded, or
/// creates unique file name on first save and uses it every time.
bool SaveToKMLFile();
/// @return nullptr in the case of error
static std::unique_ptr<BookmarkCategory> CreateFromKMLFile(std::string const & file,
size_t index,
Listeners const & listeners);
//@}
protected:
UserMark * AllocateUserMark(m2::PointD const & ptOrg) override;
private:
std::vector<std::unique_ptr<Track>> m_tracks;
void ClearTracks();
const df::MarkGroupID m_groupID;
std::string m_name;
const size_t m_index;
// Stores file name from which bookmarks were loaded.
std::string m_file;
MarkIDSet m_tracks;
};
struct BookmarkAndCategory
struct KMLData
{
BookmarkAndCategory() = default;
BookmarkAndCategory(size_t bookmarkIndex, size_t categoryIndex)
: m_bookmarkIndex(bookmarkIndex)
, m_categoryIndex(categoryIndex)
{}
bool IsValid() const
{
return m_bookmarkIndex != numeric_limits<size_t>::max() &&
m_categoryIndex != numeric_limits<size_t>::max();
};
size_t m_bookmarkIndex = numeric_limits<size_t>::max();
size_t m_categoryIndex = numeric_limits<size_t>::max();
std::string m_name;
std::string m_file;
std::vector<std::unique_ptr<Bookmark>> m_bookmarks;
std::vector<std::unique_ptr<Track>> m_tracks;
bool m_visible = true;
};
std::unique_ptr<KMLData> LoadKMLFile(std::string const & file);

File diff suppressed because it is too large Load diff

View file

@ -20,11 +20,16 @@
#include <boost/optional.hpp>
class BookmarkManager final
class BookmarkManager final : public df::UserMarksProvider
{
using CategoriesCollection = std::map<size_t, std::unique_ptr<BookmarkCategory>>;
using CategoriesCollection = std::map<df::MarkGroupID, std::unique_ptr<BookmarkCategory>>;
using MarksCollection = std::map<df::MarkID, std::unique_ptr<UserMark>>;
using BookmarksCollection = std::map<df::MarkID, std::unique_ptr<Bookmark>>;
using TracksCollection = std::map<df::MarkID, std::unique_ptr<Track>>;
using CategoryIter = CategoriesCollection::iterator;
using CategoriesIdList = std::vector<size_t>;
using GroupIdList = std::vector<df::MarkGroupID>;
using MarkIDSet = UserMarkContainer::MarkIDSet;
using UserMarkLayers = std::vector<std::unique_ptr<UserMarkContainer>>;
public:
@ -66,34 +71,92 @@ public:
explicit BookmarkManager(Callbacks && callbacks);
~BookmarkManager();
template <typename UserMarkT>
UserMarkT * CreateUserMark(m2::PointD const & ptOrg)
{
auto mark = std::make_unique<UserMarkT>(ptOrg);
auto * m = mark.get();
auto const markId = m->GetId();
auto const groupId = static_cast<df::MarkGroupID>(m->GetMarkType());
ASSERT(m_userMarks.count(markId) == 0, ());
ASSERT_LESS(groupId, m_userMarkLayers.size(), ());
m_userMarks.emplace(markId, std::move(mark));
m_userMarkLayers[groupId]->AttachUserMark(markId);
return m;
}
template <typename UserMarkT>
UserMarkT * GetMarkForEdit(df::MarkID markId)
{
auto * mark = GetUserMarkForEdit(markId);
ASSERT(dynamic_cast<UserMarkT *>(mark) != nullptr, ());
return static_cast<UserMarkT *>(mark);
}
template <typename UserMarkT>
UserMarkT const * GetMark(df::MarkID markId) const
{
auto * mark = GetUserMark(markId);
ASSERT(dynamic_cast<UserMarkT const *>(mark) != nullptr, ());
return static_cast<UserMarkT const *>(mark);
}
template <typename UserMarkT, typename F>
void DeleteUserMarks(UserMark::Type type, F deletePredicate)
{
std::list<df::MarkID> marksToDelete;
for (auto markId : GetUserMarkIds(type))
{
if (deletePredicate(GetMark<UserMarkT>(markId)))
marksToDelete.push_back(markId);
}
// Delete after iterating to avoid iterators invalidation issues.
for (auto markId : marksToDelete)
DeleteUserMark(markId);
};
UserMark const * GetUserMark(df::MarkID markID) const;
UserMark * GetUserMarkForEdit(df::MarkID markID);
void DeleteUserMark(df::MarkID markId);
Bookmark * CreateBookmark(m2::PointD const & ptOrg, BookmarkData & bm);
Bookmark * CreateBookmark(m2::PointD const & ptOrg, BookmarkData & bm, df::MarkGroupID groupID);
Bookmark const * GetBookmark(df::MarkID markID) const;
Bookmark * GetBookmarkForEdit(df::MarkID markID);
void AttachBookmark(df::MarkID bmId, df::MarkGroupID groupID);
void DetachBookmark(df::MarkID bmId, df::MarkGroupID groupID);
void DeleteBookmark(df::MarkID bmId);
Track * CreateTrack(m2::PolylineD const & polyline, Track::Params const & p);
Track const * GetTrack(df::MarkID trackID) const;
void AttachTrack(df::MarkID trackID, df::MarkGroupID groupID);
void DetachTrack(df::MarkID trackID, df::MarkGroupID groupID);
void DeleteTrack(df::MarkID trackID);
//////////////////
void NotifyChanges(size_t categoryId);
size_t GetUserMarkCount(size_t categoryId) const;
UserMark const * GetUserMark(size_t categoryId, size_t index) const;
UserMark * GetUserMarkForEdit(size_t categoryId, size_t index);
void DeleteUserMark(size_t categoryId, size_t index);
void ClearUserMarks(size_t categoryId);
Bookmark const * GetBookmark(size_t categoryId, size_t bmIndex) const;
Bookmark * GetBookmarkForEdit(size_t categoryId, size_t bmIndex);
size_t GetTracksCount(size_t categoryId) const;
Track const * GetTrack(size_t categoryId, size_t index) const;
void DeleteTrack(size_t categoryId, size_t index);
bool SaveToKMLFile(size_t categoryId);
std::string const & GetCategoryName(size_t categoryId) const;
void SetCategoryName(size_t categoryId, std::string const & name);
std::string const & GetCategoryFileName(size_t categoryId) const;
void ClearUserMarks(df::MarkGroupID groupID);
UserMark const * FindMarkInRect(size_t categoryId, m2::AnyRectD const & rect, double & d) const;
void NotifyChanges(df::MarkGroupID groupID);
UserMark * CreateUserMark(size_t categoryId, m2::PointD const & ptOrg);
MarkIDSet const & GetUserMarkIds(df::MarkGroupID groupID) const;
MarkIDSet const & GetTrackIds(df::MarkGroupID groupID) const;
void SetIsVisible(size_t categoryId, bool visible);
bool IsVisible(size_t categoryId) const;
std::string const & GetCategoryName(df::MarkGroupID categoryId) const;
void SetCategoryName(df::MarkGroupID categoryId, std::string const & name);
/// Get valid file name from input (remove illegal symbols).
static std::string RemoveInvalidSymbols(std::string const & name);
/// Get unique bookmark file name from path and valid file name.
static std::string GenerateUniqueFileName(const std::string & path, std::string name);
UserMark const * FindMarkInRect(df::MarkGroupID categoryId, m2::AnyRectD const & rect, double & d) const;
void SetIsVisible(df::MarkGroupID categoryId, bool visible);
bool IsVisible(df::MarkGroupID categoryId) const;
/// Uses the same file name from which was loaded, or
/// creates unique file name on first save and uses it every time.
bool SaveToKMLFile(df::MarkGroupID groupID);
/// @name This fuctions is public for unit tests only.
/// You don't need to call it from client code.
void SaveToKML(BookmarkCategory * group, std::ostream & s);
std::string const & GetCategoryFileName(df::MarkGroupID categoryId) const;
//////////////////
void SetDrapeEngine(ref_ptr<df::DrapeEngine> engine);
@ -109,49 +172,58 @@ public:
void InitBookmarks();
/// Client should know where it adds bookmark
size_t AddBookmark(size_t categoryIndex, m2::PointD const & ptOrg, BookmarkData & bm);
/// Client should know where it moves bookmark
size_t MoveBookmark(size_t bmIndex, size_t curCatIndex, size_t newCatIndex);
void ReplaceBookmark(size_t catIndex, size_t bmIndex, BookmarkData const & bm);
void MoveBookmark(df::MarkID bmID, df::MarkGroupID curGroupID, df::MarkGroupID newGroupID);
void UpdateBookmark(df::MarkID bmId, BookmarkData const & bm);
size_t LastEditedBMCategory();
df::MarkGroupID LastEditedBMCategory();
std::string LastEditedBMType() const;
CategoriesIdList const & GetBmCategoriesIds() const { return m_categoriesIdList; }
bool HasBmCategory(size_t categoryId) const;
GroupIdList const & GetBmGroupsIdList() const { return m_bmGroupsIdList; }
bool HasBmCategory(df::MarkGroupID groupID) const;
size_t CreateBmCategory(std::string const & name);
df::MarkGroupID CreateBmCategory(std::string const & name);
/// @name Delete bookmarks category with all bookmarks.
/// @return true if category was deleted
bool DeleteBmCategory(size_t categoryId);
bool DeleteBmCategory(df::MarkGroupID groupID);
using TTouchRectHolder = function<m2::AnyRectD(UserMark::Type)>;
Bookmark const * GetBookmark(df::MarkID id) const;
Bookmark const * GetBookmark(df::MarkID id, size_t & catIndex, size_t & bmIndex) const;
UserMark const * FindNearestUserMark(m2::AnyRectD const & rect) const;
UserMark const * FindNearestUserMark(TTouchRectHolder const & holder) const;
std::unique_ptr<StaticMarkPoint> & SelectionMark();
std::unique_ptr<StaticMarkPoint> const & SelectionMark() const;
std::unique_ptr<MyPositionMarkPoint> & MyPositionMark();
std::unique_ptr<MyPositionMarkPoint> const & MyPositionMark() const;
StaticMarkPoint & SelectionMark() { return *m_selectionMark; }
StaticMarkPoint const & SelectionMark() const { return *m_selectionMark; }
MyPositionMarkPoint & MyPositionMark() { return *m_myPositionMark; }
MyPositionMarkPoint const & MyPositionMark() const { return *m_myPositionMark; }
bool IsAsyncLoadingInProgress() const { return m_asyncLoadingInProgress; }
void AcceptChanges(df::MarkGroupID groupID,
df::MarkIDCollection & groupMarks,
df::MarkIDCollection & createdMarks,
df::MarkIDCollection & removedMarks) override;
df::UserPointMark const * GetUserPointMark(df::MarkID markID) const override;
df::UserLineMark const * GetUserLineMark(df::MarkID markID) const override;
private:
UserMarkContainer const * FindContainer(size_t containerId) const;
UserMarkContainer * FindContainer(size_t containerId);
BookmarkCategory * GetBmCategory(size_t categoryId) const;
using KMLDataCollection = std::vector<std::unique_ptr<KMLData>>;
bool IsBookmark(df::MarkGroupID groupId) const { return groupId >= UserMark::BOOKMARK; }
UserMarkContainer const * FindContainer(df::MarkGroupID containerId) const;
UserMarkContainer * FindContainer(df::MarkGroupID containerId);
BookmarkCategory * GetBmCategory(df::MarkGroupID categoryId) const;
Bookmark * AddBookmark(std::unique_ptr<Bookmark> && bookmark);
Track * AddTrack(std::unique_ptr<Track> && track);
void SaveState() const;
void LoadState();
void MergeCategories(CategoriesCollection && newCategories);
void CreateCategories(KMLDataCollection && dataCollection);
void NotifyAboutStartAsyncLoading();
void NotifyAboutFinishAsyncLoading(std::shared_ptr<CategoriesCollection> && collection);
void NotifyAboutFinishAsyncLoading(std::shared_ptr<KMLDataCollection> && collection);
boost::optional<std::string> GetKMLPath(std::string const & filePath);
void NotifyAboutFile(bool success, std::string const & filePath, bool isTemporaryFile);
void LoadBookmarkRoutine(std::string const & filePath, bool isTemporaryFile);
@ -159,7 +231,7 @@ private:
void OnCreateUserMarks(UserMarkContainer const & container, df::IDCollection const & markIds);
void OnUpdateUserMarks(UserMarkContainer const & container, df::IDCollection const & markIds);
void OnDeleteUserMarks(UserMarkContainer const & container, df::IDCollection const & markIds);
void GetBookmarksData(UserMarkContainer const & container, df::IDCollection const & markIds,
void GetBookmarksData(df::IDCollection const & markIds,
std::vector<std::pair<df::MarkID, BookmarkData>> & data) const;
Callbacks m_callbacks;
@ -168,19 +240,25 @@ private:
df::DrapeEngineSafePtr m_drapeEngine;
AsyncLoadingCallbacks m_asyncLoadingCallbacks;
std::atomic<bool> m_needTeardown;
std::atomic<size_t> m_nextCategoryId;
df::MarkGroupID m_nextGroupID;
bool m_loadBookmarksFinished = false;
ScreenBase m_viewport;
CategoriesCollection m_categories;
CategoriesIdList m_categoriesIdList;
GroupIdList m_bmGroupsIdList;
std::string m_lastCategoryUrl;
std::string m_lastType;
UserMarkLayers m_userMarkLayers;
std::unique_ptr<StaticMarkPoint> m_selectionMark;
std::unique_ptr<MyPositionMarkPoint> m_myPositionMark;
uint64_t m_generation;
MarksCollection m_userMarks;
BookmarksCollection m_bookmarks;
TracksCollection m_tracks;
StaticMarkPoint* m_selectionMark;
MyPositionMarkPoint* m_myPositionMark;
bool m_asyncLoadingInProgress = false;
struct BookmarkLoaderInfo

View file

@ -257,7 +257,7 @@ LocalAdsManager & Framework::GetLocalAdsManager()
void Framework::OnUserPositionChanged(m2::PointD const & position, bool hasPosition)
{
GetBookmarkManager().MyPositionMark()->SetUserPosition(position, hasPosition);
GetBookmarkManager().MyPositionMark().SetUserPosition(position, hasPosition);
m_routingManager.SetUserCurrentPosition(position);
m_trafficManager.UpdateMyPosition(TrafficManager::MyPosition(position));
}
@ -733,24 +733,24 @@ void Framework::LoadBookmarks()
GetBookmarkManager().LoadBookmarks();
}
size_t Framework::AddBookmark(size_t categoryIndex, const m2::PointD & ptOrg, BookmarkData & bm)
df::MarkID Framework::AddBookmark(df::MarkGroupID catId, const m2::PointD & ptOrg, BookmarkData & bm)
{
GetPlatform().GetMarketingService().SendMarketingEvent(marketing::kBookmarksBookmarkAction,
{{"action", "create"}});
return GetBookmarkManager().AddBookmark(categoryIndex, ptOrg, bm);
return GetBookmarkManager().CreateBookmark(ptOrg, bm, catId)->GetId();
}
size_t Framework::MoveBookmark(size_t bmIndex, size_t curCatIndex, size_t newCatIndex)
void Framework::MoveBookmark(df::MarkID bmId, df::MarkGroupID curCatId, df::MarkGroupID newCatId)
{
return GetBookmarkManager().MoveBookmark(bmIndex, curCatIndex, newCatIndex);
return GetBookmarkManager().MoveBookmark(bmId, curCatId, newCatId);
}
void Framework::ReplaceBookmark(size_t catIndex, size_t bmIndex, BookmarkData const & bm)
void Framework::ReplaceBookmark(df::MarkID bmId, BookmarkData const & bm)
{
GetBookmarkManager().ReplaceBookmark(catIndex, bmIndex, bm);
GetBookmarkManager().UpdateBookmark(bmId, bm);
}
size_t Framework::AddCategory(string const & categoryName)
df::MarkGroupID Framework::AddCategory(string const & categoryName)
{
return GetBookmarkManager().CreateBmCategory(categoryName);
}
@ -760,12 +760,12 @@ bool Framework::DeleteBmCategory(size_t index)
return GetBookmarkManager().DeleteBmCategory(index);
}
void Framework::FillBookmarkInfo(Bookmark const & bmk, BookmarkAndCategory const & bac, place_page::Info & info) const
void Framework::FillBookmarkInfo(Bookmark const & bmk, place_page::Info & info) const
{
info.SetBookmarkCategoryName(GetBookmarkManager().GetCategoryName(bac.m_categoryIndex));
BookmarkData const & data = GetBookmarkManager().GetBookmark(bac.m_categoryIndex, bac.m_bookmarkIndex)->GetData();
info.SetBookmarkData(data);
info.SetBac(bac);
info.SetBookmarkCategoryName(GetBookmarkManager().GetCategoryName(bmk.GetGroupId()));
info.SetBookmarkData(bmk.GetData());
info.SetBookmarkId(bmk.GetId());
info.SetBookmarkCategoryId(bmk.GetGroupId());
FillPointInfo(bmk.GetPivot(), {} /* customTitle */, info);
}
@ -773,7 +773,8 @@ void Framework::ResetBookmarkInfo(Bookmark const & bmk, place_page::Info & info)
{
info.SetBookmarkCategoryName("");
info.SetBookmarkData({});
info.SetBac({});
info.SetBookmarkId(0);
info.SetBookmarkCategoryId(0);
FillPointInfo(bmk.GetPivot(), {} /* customTitle */, info);
}
@ -989,18 +990,11 @@ void Framework::FillRouteMarkInfo(RouteMarkPoint const & rmp, place_page::Info &
void Framework::ShowBookmark(df::MarkID id)
{
BookmarkAndCategory bnc;
auto const mark = m_bmManager->GetBookmark(id, bnc.m_categoryIndex, bnc.m_bookmarkIndex);
ShowBookmark(mark, bnc);
auto const * mark = m_bmManager->GetBookmark(id);
ShowBookmark(mark);
}
void Framework::ShowBookmark(BookmarkAndCategory const & bnc)
{
auto const bookmark = GetBookmarkManager().GetBookmark(bnc.m_categoryIndex, bnc.m_bookmarkIndex);
ShowBookmark(bookmark, bnc);
}
void Framework::ShowBookmark(Bookmark const * mark, BookmarkAndCategory const & bnc)
void Framework::ShowBookmark(Bookmark const * mark)
{
if (mark == nullptr)
return;
@ -1016,7 +1010,7 @@ void Framework::ShowBookmark(Bookmark const * mark, BookmarkAndCategory const &
true /* trackVisibleViewport */);
place_page::Info info;
FillBookmarkInfo(*mark, bnc, info);
FillBookmarkInfo(*mark, info);
ActivateMapSelection(true, df::SelectionShape::OBJECT_USER_MARK, info);
// TODO
// We need to preserve bookmark id in the m_lastTapEvent, because one feature can have several bookmarks.
@ -1044,7 +1038,7 @@ void Framework::ShowFeatureByMercator(m2::PointD const & pt)
place_page::Info info;
std::string name;
GetBookmarkManager().SelectionMark()->SetPtOrg(pt);
GetBookmarkManager().SelectionMark().SetPtOrg(pt);
FillPointInfo(pt, name, info);
ActivateMapSelection(false, df::SelectionShape::OBJECT_POI, info);
m_lastTapEvent = MakeTapEvent(info.GetMercator(), info.GetID(), TapEvent::Source::Other);
@ -1519,7 +1513,7 @@ void Framework::SelectSearchResult(search::Result const & result, bool animation
if (m_drapeEngine != nullptr)
m_drapeEngine->SetModelViewCenter(center, scale, animation, true /* trackVisibleViewport */);
GetBookmarkManager().SelectionMark()->SetPtOrg(center);
GetBookmarkManager().SelectionMark().SetPtOrg(center);
ActivateMapSelection(false, df::SelectionShape::OBJECT_POI, info);
m_lastTapEvent = MakeTapEvent(center, info.GetID(), TapEvent::Source::Search);
}
@ -1620,8 +1614,7 @@ void Framework::FillSearchResultsMarks(bool clear, search::Results::ConstIter be
if (!r.HasPoint())
continue;
auto mark = static_cast<SearchMarkPoint *>(bmManager.CreateUserMark(UserMark::Type::SEARCH, r.GetFeatureCenter()));
ASSERT_EQUAL(mark->GetMarkType(), UserMark::Type::SEARCH, ());
auto * mark = bmManager.CreateUserMark<SearchMarkPoint>(r.GetFeatureCenter());
auto const isFeature = r.GetResultType() == search::Result::Type::Feature;
if (isFeature)
mark->SetFoundFeature(r.GetFeatureID());
@ -2017,7 +2010,7 @@ bool Framework::ShowMapForURL(string const & url)
}
else
{
GetBookmarkManager().SelectionMark()->SetPtOrg(point);
GetBookmarkManager().SelectionMark().SetPtOrg(point);
FillPointInfo(point, name, info);
ActivateMapSelection(false, df::SelectionShape::OBJECT_POI, info);
}
@ -2114,29 +2107,6 @@ BookmarkManager const & Framework::GetBookmarkManager() const
return *m_bmManager.get();
}
BookmarkAndCategory Framework::FindBookmark(UserMark const * mark) const
{
Bookmark const * bookmark = static_cast<Bookmark const *>(mark);
BookmarkAndCategory empty;
BookmarkAndCategory result;
ASSERT_LESS_OR_EQUAL(GetBookmarkManager().GetBmCategoriesIds().size(), numeric_limits<int>::max(), ());
result.m_categoryIndex = bookmark->GetCategoryId();
ASSERT(result.m_categoryIndex != empty.m_categoryIndex, ());
size_t const sz = GetBookmarkManager().GetUserMarkCount(result.m_categoryIndex);
ASSERT_LESS_OR_EQUAL(sz, numeric_limits<int>::max(), ());
for (size_t i = 0; i < sz; ++i)
{
if (bookmark == GetBookmarkManager().GetBookmark(result.m_categoryIndex, i))
{
result.m_bookmarkIndex = static_cast<int>(i);
break;
}
}
ASSERT(result.IsValid(), ());
return result;
}
void Framework::SetMapSelectionListeners(TActivateMapSelectionFn const & activator,
TDeactivateMapSelectionFn const & deactivator)
{
@ -2313,7 +2283,7 @@ FeatureID Framework::FindBuildingAtPoint(m2::PointD const & mercator) const
}
df::SelectionShape::ESelectedObject Framework::OnTapEventImpl(TapEvent const & tapEvent,
place_page::Info & outInfo) const
place_page::Info & outInfo)
{
if (m_drapeEngine == nullptr)
return df::SelectionShape::OBJECT_EMPTY;
@ -2337,7 +2307,7 @@ df::SelectionShape::ESelectedObject Framework::OnTapEventImpl(TapEvent const & t
FillApiMarkInfo(*static_cast<ApiMarkPoint const *>(mark), outInfo);
break;
case UserMark::Type::BOOKMARK:
FillBookmarkInfo(*static_cast<Bookmark const *>(mark), FindBookmark(mark), outInfo);
FillBookmarkInfo(*static_cast<Bookmark const *>(mark), outInfo);
break;
case UserMark::Type::SEARCH:
FillSearchResultInfo(*static_cast<SearchMarkPoint const *>(mark), outInfo);
@ -2370,7 +2340,7 @@ df::SelectionShape::ESelectedObject Framework::OnTapEventImpl(TapEvent const & t
if (showMapSelection)
{
GetBookmarkManager().SelectionMark()->SetPtOrg(outInfo.GetMercator());
GetBookmarkManager().SelectionMark().SetPtOrg(outInfo.GetMercator());
return df::SelectionShape::OBJECT_POI;
}
@ -3220,9 +3190,9 @@ void Framework::ClearViewportSearchResults()
boost::optional<m2::PointD> Framework::GetCurrentPosition() const
{
auto const & myPosMark = GetBookmarkManager().MyPositionMark();
if (!myPosMark->HasPosition())
if (!myPosMark.HasPosition())
return {};
return myPosMark->GetPivot();
return myPosMark.GetPivot();
}
bool Framework::ParseSearchQueryCommand(search::SearchParams const & params)

View file

@ -315,13 +315,12 @@ public:
/// Scans and loads all kml files with bookmarks in WritableDir.
void LoadBookmarks();
/// @return Created bookmark index in category.
size_t AddBookmark(size_t categoryIndex, m2::PointD const & ptOrg, BookmarkData & bm);
/// @return New moved bookmark index in category.
size_t MoveBookmark(size_t bmIndex, size_t curCatIndex, size_t newCatIndex);
void ReplaceBookmark(size_t catIndex, size_t bmIndex, BookmarkData const & bm);
/// @return Created bookmark category index.
size_t AddCategory(string const & categoryName);
/// @return Created bookmark id.
df::MarkID AddBookmark(df::MarkGroupID catId, m2::PointD const & ptOrg, BookmarkData & bm);
void MoveBookmark(df::MarkID bmId, df::MarkGroupID curCatId, df::MarkGroupID newCatId);
void ReplaceBookmark(df::MarkID bmId, BookmarkData const & bm);
/// @return Created bookmark category id.
df::MarkGroupID AddCategory(string const & categoryName);
size_t LastEditedBMCategory() { return GetBookmarkManager().LastEditedBMCategory(); }
string LastEditedBMType() const { return GetBookmarkManager().LastEditedBMType(); }
@ -331,7 +330,7 @@ public:
bool DeleteBmCategory(size_t index);
void ShowBookmark(df::MarkID id);
void ShowBookmark(BookmarkAndCategory const & bnc);
void ShowBookmark(Bookmark const * bookmark);
void ShowTrack(Track const & track);
void ShowFeatureByMercator(m2::PointD const & pt);
@ -339,7 +338,6 @@ public:
void AddBookmarksFile(string const & filePath, bool isTemporaryFile);
BookmarkAndCategory FindBookmark(UserMark const * mark) const;
BookmarkManager & GetBookmarkManager();
BookmarkManager const & GetBookmarkManager() const;
@ -365,7 +363,6 @@ private:
df::SelectionShape::ESelectedObject selectionType,
place_page::Info const & info);
void InvalidateUserMarks();
void ShowBookmark(Bookmark const * bookmark, BookmarkAndCategory const & bnc);
public:
void DeactivateMapSelection(bool notifyUI);
@ -423,7 +420,7 @@ private:
void OnTapEvent(TapEvent const & tapEvent);
/// outInfo is valid only if return value is not df::SelectionShape::OBJECT_EMPTY.
df::SelectionShape::ESelectedObject OnTapEventImpl(TapEvent const & tapEvent,
place_page::Info & outInfo) const;
place_page::Info & outInfo);
unique_ptr<TapEvent> MakeTapEvent(m2::PointD const & center, FeatureID const & fid,
TapEvent::Source source) const;
UserMark const * FindUserMarkInTapPosition(df::TapInfo const & tapInfo) const;
@ -661,7 +658,7 @@ private:
void FillRouteMarkInfo(RouteMarkPoint const & rmp, place_page::Info & info) const;
public:
void FillBookmarkInfo(Bookmark const & bmk, BookmarkAndCategory const & bac, place_page::Info & info) const;
void FillBookmarkInfo(Bookmark const & bmk, place_page::Info & info) const;
void ResetBookmarkInfo(Bookmark const & bmk, place_page::Info & info) const;
/// @returns address of nearby building with house number in approx 1km distance.

View file

@ -146,9 +146,7 @@ void CreateLocalAdsMarks(BookmarkManager * bmManager, CampaignData const & campa
{
for (auto const & data : campaignData)
{
auto userMark = bmManager->CreateUserMark(UserMark::Type::LOCAL_ADS, data.second.m_position);
ASSERT(dynamic_cast<LocalAdsMark *>(userMark) != nullptr, ());
LocalAdsMark * mark = static_cast<LocalAdsMark *>(userMark);
auto * mark = bmManager->CreateUserMark<LocalAdsMark>(data.second.m_position);
mark->SetData(LocalAdsMarkData(data.second));
mark->SetFeatureId(data.first);
}
@ -163,16 +161,11 @@ void DeleteLocalAdsMarks(BookmarkManager * bmManager, MwmSet::MwmId const & mwmI
GetPlatform().RunTask(Platform::Thread::Gui, [bmManager, mwmId]()
{
for (size_t i = 0; i < bmManager->GetUserMarkCount(UserMark::Type::LOCAL_ADS);)
{
auto userMark = bmManager->GetUserMark(UserMark::Type::LOCAL_ADS, i);
ASSERT(dynamic_cast<LocalAdsMark const *>(userMark) != nullptr, ());
LocalAdsMark const * mark = static_cast<LocalAdsMark const *>(userMark);
if (mark->GetFeatureID().m_mwmId == mwmId)
bmManager->DeleteUserMark(UserMark::Type::LOCAL_ADS, i);
else
++i;
}
bmManager->DeleteUserMarks<LocalAdsMark>(UserMark::Type::LOCAL_ADS,
[&mwmId](LocalAdsMark const * mark)
{
return mark->GetFeatureID().m_mwmId == mwmId;
});
bmManager->NotifyChanges(UserMark::Type::LOCAL_ADS);
});
}

View file

@ -196,7 +196,7 @@ ParsedMapApi::ParsingResult ParsedMapApi::Parse(Uri const & uri)
for (auto const & p : points)
{
m2::PointD glPoint(MercatorBounds::FromLatLon(p.m_lat, p.m_lon));
ApiMarkPoint * mark = static_cast<ApiMarkPoint *>(m_bmManager->CreateUserMark(UserMark::Type::API, glPoint));
auto * mark = m_bmManager->CreateUserMark<ApiMarkPoint>(glPoint);
mark->SetName(p.m_name);
mark->SetApiID(p.m_id);
mark->SetStyle(style::GetSupportedStyle(p.m_style, p.m_name, ""));
@ -446,18 +446,18 @@ void ParsedMapApi::Reset()
bool ParsedMapApi::GetViewportRect(m2::RectD & rect) const
{
ASSERT(m_bmManager != nullptr, ());
size_t const markCount = m_bmManager->GetUserMarkCount(UserMark::Type::API);
if (markCount == 1 && m_zoomLevel >= 1)
auto const & markIds = m_bmManager->GetUserMarkIds(UserMark::Type::API);
if (markIds.size() == 1 && m_zoomLevel >= 1)
{
double zoom = min(static_cast<double>(scales::GetUpperComfortScale()), m_zoomLevel);
rect = df::GetRectForDrawScale(zoom, m_bmManager->GetUserMark(UserMark::Type::API, 0)->GetPivot());
rect = df::GetRectForDrawScale(zoom, m_bmManager->GetUserMark(*markIds.begin())->GetPivot());
return true;
}
else
{
m2::RectD result;
for (size_t i = 0; i < markCount; ++i)
result.Add(m_bmManager->GetUserMark(UserMark::Type::API, i)->GetPivot());
for (auto markId : markIds)
result.Add(m_bmManager->GetUserMark(markId)->GetPivot());
if (result.IsValid())
{
@ -472,10 +472,11 @@ bool ParsedMapApi::GetViewportRect(m2::RectD & rect) const
ApiMarkPoint const * ParsedMapApi::GetSinglePoint() const
{
ASSERT(m_bmManager != nullptr, ());
if (m_bmManager->GetUserMarkCount(UserMark::Type::API) != 1)
auto const & markIds = m_bmManager->GetUserMarkIds(UserMark::Type::API);
if (markIds.size() != 1)
return nullptr;
return static_cast<ApiMarkPoint const *>(m_bmManager->GetUserMark(UserMark::Type::API, 0));
return static_cast<ApiMarkPoint const *>(m_bmManager->GetUserMark(*markIds.begin()));
}
}

View file

@ -186,9 +186,9 @@ void Info::SetCustomNameWithCoordinates(m2::PointD const & mercator, std::string
m_customName = name;
}
void Info::SetBac(BookmarkAndCategory const & bac)
void Info::SetBookmarkId(df::MarkID markId)
{
m_bac = bac;
m_markId = markId;
m_uiSubtitle = FormatSubtitle(IsFeature() /* withType */);
}

View file

@ -69,7 +69,7 @@ public:
/// Place traits
bool IsFeature() const { return m_featureID.IsValid(); }
bool IsBookmark() const { return m_bac.IsValid(); }
bool IsBookmark() const { return m_markGroupId != 0; }
bool IsMyPosition() const { return m_isMyPosition; }
bool IsRoutePoint() const { return m_isRoutePoint; }
@ -116,9 +116,11 @@ public:
void SetLocalizedWifiString(std::string const & str) { m_localizedWifiString = str; }
/// Bookmark
BookmarkAndCategory const & GetBookmarkAndCategory() const { return m_bac; }
void SetBookmarkId(df::MarkID markId);
df::MarkID GetBookmarkId() const { return m_markId; }
void SetBookmarkCategoryId(df::MarkGroupID markGroupId) { m_markGroupId = markGroupId; }
df::MarkGroupID GetBookmarkCategoryId() const { return m_markGroupId; }
std::string const & GetBookmarkCategoryName() const { return m_bookmarkCategoryName; }
void SetBac(BookmarkAndCategory const & bac);
void SetBookmarkCategoryName(std::string const & name) { m_bookmarkCategoryName = name; }
void SetBookmarkData(BookmarkData const & data) { m_bookmarkData = data; }
BookmarkData const & GetBookmarkData() const { return m_bookmarkData; }
@ -235,7 +237,8 @@ private:
/// Bookmarks
/// If not empty, bookmark is bound to this place page.
BookmarkAndCategory m_bac;
df::MarkID m_markId = 0;
df::MarkGroupID m_markGroupId = 0;
/// Bookmark category name. Empty, if it's not bookmark;
std::string m_bookmarkCategoryName;
BookmarkData m_bookmarkData;

View file

@ -110,7 +110,7 @@ RouteMarkData GetLastPassedPoint(BookmarkManager * bmManager, vector<RouteMarkDa
data.m_intermediateIndex = 0;
if (data.m_isMyPosition)
{
data.m_position = bmManager->MyPositionMark()->GetPivot();
data.m_position = bmManager->MyPositionMark().GetPivot();
data.m_isMyPosition = false;
}
@ -247,10 +247,9 @@ RoutingManager::RoutingManager(Callbacks && callbacks, Delegate & delegate)
#ifdef SHOW_ROUTE_DEBUG_MARKS
if (m_bmManager == nullptr)
return;
auto & controller = m_bmManager->GetUserMarksController(UserMark::Type::DEBUG_MARK);
controller.SetIsVisible(true);
controller.CreateUserMark(pt);
controller.NotifyChanges();
m_bmManager->SetIsVisible(UserMark::Type::DEBUG_MARK, true);
m_bmManager->CreateUserMark<DebugMarkPoint>(pt);
m_bmManager->NotifyChanges(UserMark::Type::DEBUG_MARK);
#endif
});
@ -629,7 +628,8 @@ bool RoutingManager::CouldAddIntermediatePoint() const
if (!IsRoutingActive())
return false;
return m_bmManager->GetUserMarkCount(UserMark::Type::ROUTING) < RoutePointsLayout::kMaxIntermediatePointsCount + 2;
return m_bmManager->GetUserMarkIds(UserMark::Type::ROUTING).size()
< RoutePointsLayout::kMaxIntermediatePointsCount + 2;
}
void RoutingManager::AddRoutePoint(RouteMarkData && markData)
@ -802,12 +802,12 @@ void RoutingManager::BuildRoute(uint32_t timeoutSec)
continue;
auto const & myPosition = m_bmManager->MyPositionMark();
if (!myPosition->HasPosition())
if (!myPosition.HasPosition())
{
CallRouteBuilded(IRouter::NoCurrentPosition, storage::TCountriesVec());
return;
}
p.m_position = myPosition->GetPivot();
p.m_position = myPosition.GetPivot();
}
// Check for equal points.
@ -1172,12 +1172,12 @@ bool RoutingManager::LoadRoutePoints()
m_bmManager->ClearUserMarks(UserMark::Type::ROUTING);
for (auto & p : points)
{
if (p.m_pointType == RouteMarkType::Start && myPosMark->HasPosition())
if (p.m_pointType == RouteMarkType::Start && myPosMark.HasPosition())
{
RouteMarkData startPt;
startPt.m_pointType = RouteMarkType::Start;
startPt.m_isMyPosition = true;
startPt.m_position = myPosMark->GetPivot();
startPt.m_position = myPosMark.GetPivot();
AddRoutePoint(move(startPt));
}
else
@ -1188,7 +1188,7 @@ bool RoutingManager::LoadRoutePoints()
// If we don't have my position, save loading timestamp. Probably
// we will get my position soon.
if (!myPosMark->HasPosition())
if (!myPosMark.HasPosition())
m_loadRoutePointsTimestamp = chrono::steady_clock::now();
return true;

View file

@ -178,7 +178,7 @@ RoutePointsLayout::RoutePointsLayout(BookmarkManager & manager)
RouteMarkPoint * RoutePointsLayout::AddRoutePoint(RouteMarkData && data)
{
auto const count = m_manager.GetUserMarkCount(UserMark::Type::ROUTING);
auto const count = m_manager.GetUserMarkIds(UserMark::Type::ROUTING).size();
if (count == kMaxIntermediatePointsCount + 2)
return nullptr;
@ -216,9 +216,7 @@ RouteMarkPoint * RoutePointsLayout::AddRoutePoint(RouteMarkData && data)
}
}
}
auto userMark = m_manager.CreateUserMark(UserMark::Type::ROUTING, data.m_position);
ASSERT(dynamic_cast<RouteMarkPoint *>(userMark) != nullptr, ());
RouteMarkPoint * newPoint = static_cast<RouteMarkPoint *>(userMark);
auto * newPoint = m_manager.CreateUserMark<RouteMarkPoint>(data.m_position);
newPoint->SetMarkData(std::move(data));
return newPoint;
@ -226,11 +224,10 @@ RouteMarkPoint * RoutePointsLayout::AddRoutePoint(RouteMarkData && data)
bool RoutePointsLayout::RemoveRoutePoint(RouteMarkType type, size_t intermediateIndex)
{
RouteMarkPoint * point = nullptr;
size_t index = 0;
for (size_t sz = m_manager.GetUserMarkCount(UserMark::Type::ROUTING); index < sz; ++index)
RouteMarkPoint const * point = nullptr;
for (auto markId : m_manager.GetUserMarkIds(UserMark::Type::ROUTING))
{
RouteMarkPoint * mark = GetRouteMarkForEdit(index);
auto const * mark = m_manager.GetMark<RouteMarkPoint>(markId);
if (mark->IsEqualFullType(type, intermediateIndex))
{
point = mark;
@ -276,7 +273,7 @@ bool RoutePointsLayout::RemoveRoutePoint(RouteMarkType type, size_t intermediate
});
}
m_manager.DeleteUserMark(UserMark::Type::ROUTING, index);
m_manager.DeleteUserMark(point->GetId());
return true;
}
@ -287,17 +284,11 @@ void RoutePointsLayout::RemoveRoutePoints()
void RoutePointsLayout::RemoveIntermediateRoutePoints()
{
for (size_t i = 0, sz = m_manager.GetUserMarkCount(UserMark::Type::ROUTING); i < sz;)
{
RouteMarkPoint const * mark = GetRouteMark(i);
if (mark->GetRoutePointType() == RouteMarkType::Intermediate)
{
m_manager.DeleteUserMark(UserMark::Type::ROUTING, i);
--sz;
}
else
++i;
}
m_manager.DeleteUserMarks<RouteMarkPoint>(UserMark::Type::ROUTING,
[](RouteMarkPoint const * mark)
{
return mark->GetRoutePointType() == RouteMarkType::Intermediate;
});
}
bool RoutePointsLayout::MoveRoutePoint(RouteMarkType currentType, size_t currentIntermediateIndex,
@ -328,42 +319,42 @@ void RoutePointsLayout::PassRoutePoint(RouteMarkType type, size_t intermediateIn
void RoutePointsLayout::SetFollowingMode(bool enabled)
{
for (size_t i = 0, sz = m_manager.GetUserMarkCount(UserMark::Type::ROUTING); i < sz; ++i)
GetRouteMarkForEdit(i)->SetFollowingMode(enabled);
for (auto markId : m_manager.GetUserMarkIds(UserMark::Type::ROUTING))
m_manager.GetMarkForEdit<RouteMarkPoint>(markId)->SetFollowingMode(enabled);
}
RouteMarkPoint * RoutePointsLayout::GetRoutePoint(RouteMarkType type, size_t intermediateIndex)
{
for (size_t i = 0, sz = m_manager.GetUserMarkCount(UserMark::Type::ROUTING); i < sz; ++i)
for (auto markId : m_manager.GetUserMarkIds(UserMark::Type::ROUTING))
{
RouteMarkPoint * mark = GetRouteMarkForEdit(i);
auto const * mark = m_manager.GetMark<RouteMarkPoint>(markId);
if (mark->IsEqualFullType(type, intermediateIndex))
return mark;
return m_manager.GetMarkForEdit<RouteMarkPoint>(markId);
}
return nullptr;
}
RouteMarkPoint * RoutePointsLayout::GetMyPositionPoint()
{
for (size_t i = 0, sz = m_manager.GetUserMarkCount(UserMark::Type::ROUTING); i < sz; ++i)
for (auto markId : m_manager.GetUserMarkIds(UserMark::Type::ROUTING))
{
RouteMarkPoint * mark = GetRouteMarkForEdit(i);
auto const * mark = m_manager.GetMark<RouteMarkPoint>(markId);
if (mark->IsMyPosition())
return mark;
return m_manager.GetMarkForEdit<RouteMarkPoint>(markId);
}
return nullptr;
}
std::vector<RouteMarkPoint *> RoutePointsLayout::GetRoutePoints()
{
size_t const sz = m_manager.GetUserMarkCount(UserMark::Type::ROUTING);
auto const & markIds = m_manager.GetUserMarkIds(UserMark::Type::ROUTING);
std::vector<RouteMarkPoint *> points;
points.reserve(sz);
points.reserve(markIds.size());
RouteMarkPoint * startPoint = nullptr;
RouteMarkPoint * finishPoint = nullptr;
for (size_t i = 0; i < sz; ++i)
for (auto markId : markIds)
{
RouteMarkPoint * p = GetRouteMarkForEdit(i);
auto * p = m_manager.GetMarkForEdit<RouteMarkPoint>(markId);
if (p->GetRoutePointType() == RouteMarkType::Start)
startPoint = p;
else if (p->GetRoutePointType() == RouteMarkType::Finish)
@ -384,28 +375,14 @@ std::vector<RouteMarkPoint *> RoutePointsLayout::GetRoutePoints()
size_t RoutePointsLayout::GetRoutePointsCount() const
{
return m_manager.GetUserMarkCount(UserMark::Type::ROUTING);
}
RouteMarkPoint * RoutePointsLayout::GetRouteMarkForEdit(size_t index)
{
auto userMark = m_manager.GetUserMarkForEdit(UserMark::Type::ROUTING, index);
ASSERT(dynamic_cast<RouteMarkPoint *>(userMark) != nullptr, ());
return static_cast<RouteMarkPoint *>(userMark);
}
RouteMarkPoint const * RoutePointsLayout::GetRouteMark(size_t index)
{
auto userMark = m_manager.GetUserMark(UserMark::Type::ROUTING, index);
ASSERT(dynamic_cast<RouteMarkPoint const *>(userMark) != nullptr, ());
return static_cast<RouteMarkPoint const *>(userMark);
return m_manager.GetUserMarkIds(UserMark::Type::ROUTING).size();
}
void RoutePointsLayout::ForEachIntermediatePoint(TRoutePointCallback const & fn)
{
for (size_t i = 0, sz = m_manager.GetUserMarkCount(UserMark::Type::ROUTING); i < sz; ++i)
for (auto markId : m_manager.GetUserMarkIds(UserMark::Type::ROUTING))
{
RouteMarkPoint * mark = GetRouteMarkForEdit(i);
auto * mark = m_manager.GetMarkForEdit<RouteMarkPoint>(markId);
if (mark->GetRoutePointType() == RouteMarkType::Intermediate)
fn(mark);
}

View file

@ -97,8 +97,6 @@ public:
private:
using TRoutePointCallback = function<void (RouteMarkPoint * mark)>;
void ForEachIntermediatePoint(TRoutePointCallback const & fn);
RouteMarkPoint * GetRouteMarkForEdit(size_t index);
RouteMarkPoint const * GetRouteMark(size_t index);
BookmarkManager & m_manager;
};

View file

@ -126,10 +126,9 @@ void SearchMarks::SetPreparingState(std::vector<FeatureID> const & features, boo
ASSERT(std::is_sorted(features.begin(), features.end()), ());
size_t const count = m_bmManager->GetUserMarkCount(UserMark::Type::SEARCH);
for (size_t i = 0; i < count; ++i)
for (auto markId : m_bmManager->GetUserMarkIds(UserMark::Type::SEARCH))
{
auto mark = static_cast<SearchMarkPoint *>(m_bmManager->GetUserMarkForEdit(UserMark::Type::SEARCH, i));
auto mark = static_cast<SearchMarkPoint *>(m_bmManager->GetUserMarkForEdit(markId));
if (std::binary_search(features.begin(), features.end(), mark->GetFeatureID()))
mark->SetPreparing(isPreparing);
}

View file

@ -9,6 +9,7 @@
Track::Track(Track::PolylineD const & polyline, Track::Params const & p)
: m_polyline(polyline)
, m_params(p)
, m_groupID(0)
{
ASSERT_GREATER(m_polyline.GetSize(), 1, ());
}
@ -71,3 +72,14 @@ std::vector<m2::PointD> const & Track::GetPoints() const
{
return m_polyline.GetPoints();
}
void Track::Attach(df::MarkGroupID groupID)
{
ASSERT(!m_groupID, ());
m_groupID = groupID;
}
void Track::Detach()
{
m_groupID = 0;
}

View file

@ -50,8 +50,13 @@ public:
float GetDepth(size_t layerIndex) const override;
std::vector<m2::PointD> const & GetPoints() const override;
df::MarkGroupID GetGroupId() const { return m_groupID; }
void Attach(df::MarkGroupID groupID);
void Detach();
private:
PolylineD m_polyline;
Params m_params;
df::MarkGroupID m_groupID;
mutable bool m_isDirty = true;
};

View file

@ -122,7 +122,6 @@ void AddTransitGateSegment(m2::PointD const & destPoint, df::ColorConstant const
ASSERT_GREATER(subroute.m_polyline.GetSize(), 0, ());
df::SubrouteStyle style(color, df::RoutePattern(4.0, 2.0));
style.m_startIndex = subroute.m_polyline.GetSize() - 1;
auto const vec = destPoint - subroute.m_polyline.Back();
subroute.m_polyline.Add(destPoint);
style.m_endIndex = subroute.m_polyline.GetSize() - 1;
subroute.AddStyle(style);
@ -459,12 +458,9 @@ void TransitRouteDisplay::CollectTransitDisplayInfo(vector<RouteSegment> const &
TransitMark * TransitRouteDisplay::CreateMark(m2::PointD const & pt, FeatureID const & fid)
{
uint32_t const nextIndex = static_cast<uint32_t>(m_bmManager->GetUserMarkCount(UserMark::Type::TRANSIT));
auto userMark = m_bmManager->CreateUserMark(UserMark::Type::TRANSIT, pt);
ASSERT(dynamic_cast<TransitMark *>(userMark) != nullptr, ());
auto transitMark = static_cast<TransitMark *>(userMark);
uint32_t const nextIndex = static_cast<uint32_t>(m_bmManager->GetUserMarkIds(UserMark::Type::TRANSIT).size());
auto * transitMark = m_bmManager->CreateUserMark<TransitMark>(pt);
transitMark->SetFeatureId(fid);
transitMark->SetIndex(nextIndex);
return transitMark;

View file

@ -36,8 +36,8 @@ ms::LatLon UserMark::GetLatLon() const
return MercatorBounds::ToLatLon(m_ptOrg);
}
StaticMarkPoint::StaticMarkPoint()
: UserMark(m2::PointD{}, UserMark::Type::STATIC)
StaticMarkPoint::StaticMarkPoint(m2::PointD const & ptOrg)
: UserMark(ptOrg, UserMark::Type::STATIC)
{}
void StaticMarkPoint::SetPtOrg(m2::PointD const & ptOrg)
@ -46,8 +46,8 @@ void StaticMarkPoint::SetPtOrg(m2::PointD const & ptOrg)
m_ptOrg = ptOrg;
}
MyPositionMarkPoint::MyPositionMarkPoint()
: StaticMarkPoint()
MyPositionMarkPoint::MyPositionMarkPoint(m2::PointD const & ptOrg)
: StaticMarkPoint(ptOrg)
{}
DebugMarkPoint::DebugMarkPoint(const m2::PointD & ptOrg)

View file

@ -39,8 +39,7 @@ public:
TRANSIT,
LOCAL_ADS,
DEBUG_MARK,
BOOKMARK,
PREDEFINED_COUNT = BOOKMARK
BOOKMARK, // Should always be the last one
};
UserMark(m2::PointD const & ptOrg, UserMark::Type type);
@ -52,7 +51,7 @@ public:
m2::PointD const & GetPivot() const override;
m2::PointD GetPixelOffset() const override;
dp::Anchor GetAnchor() const override;
virtual float GetDepth() const override { return 0.0f; };
virtual float GetDepth() const override { return 0.0f; }
df::RenderState::DepthLayer GetDepthLayer() const override;
drape_ptr<TitlesInfo> GetTitleDecl() const override { return nullptr; }
drape_ptr<ColoredSymbolZoomInfo> GetColoredSymbols() const override { return nullptr; }
@ -69,6 +68,8 @@ public:
ms::LatLon GetLatLon() const;
virtual Type GetMarkType() const { return m_type; }
virtual df::MarkGroupID GetGroupId() const { return m_type; }
virtual bool IsAvailableForSearch() const { return true; }
protected:
@ -86,7 +87,7 @@ private:
class StaticMarkPoint : public UserMark
{
public:
explicit StaticMarkPoint();
explicit StaticMarkPoint(m2::PointD const & ptOrg);
drape_ptr<SymbolNameZoomInfo> GetSymbolNames() const override { return nullptr; }
@ -96,7 +97,7 @@ public:
class MyPositionMarkPoint : public StaticMarkPoint
{
public:
explicit MyPositionMarkPoint();
explicit MyPositionMarkPoint(m2::PointD const & ptOrg);
void SetUserPosition(m2::PointD const & pt, bool hasPosition)
{

View file

@ -11,105 +11,16 @@
#include <algorithm>
#include <utility>
namespace
{
class FindMarkFunctor
{
public:
FindMarkFunctor(UserMark ** mark, double & minD, m2::AnyRectD const & rect)
: m_mark(mark)
, m_minD(minD)
, m_rect(rect)
{
m_globalCenter = rect.GlobalCenter();
}
void operator()(UserMark * mark)
{
m2::PointD const & org = mark->GetPivot();
if (m_rect.IsPointInside(org))
{
double minDCandidate = m_globalCenter.SquareLength(org);
if (minDCandidate < m_minD)
{
*m_mark = mark;
m_minD = minDCandidate;
}
}
}
UserMark ** m_mark;
double & m_minD;
m2::AnyRectD const & m_rect;
m2::PointD m_globalCenter;
};
size_t const VisibleFlag = 0;
size_t const DrawableFlag = 1;
df::MarkGroupID GenerateMarkGroupId(UserMarkContainer const * cont)
{
return reinterpret_cast<df::MarkGroupID>(cont);
}
} // namespace
UserMarkContainer::UserMarkContainer(UserMark::Type type,
Listeners const & listeners)
: m_type(type)
, m_listeners(listeners)
{
m_flags.set();
}
UserMarkContainer::~UserMarkContainer()
{
Clear();
NotifyChanges();
}
void UserMarkContainer::SetDrapeEngine(ref_ptr<df::DrapeEngine> engine)
{
m_drapeEngine.Set(engine);
}
UserMark const * UserMarkContainer::GetUserMarkById(df::MarkID id) const
{
auto const it = m_userMarksDict.find(id);
if (it != m_userMarksDict.end())
return it->second;
return nullptr;
}
UserMark const * UserMarkContainer::GetUserMarkById(df::MarkID id, size_t & index) const
{
auto const it = m_userMarksDict.find(id);
if (it != m_userMarksDict.end())
{
for (size_t i = 0; i < m_userMarks.size(); ++i)
{
if (m_userMarks[i]->GetId() == id)
{
index = i;
return m_userMarks[i].get();
}
}
}
return nullptr;
}
UserMark const * UserMarkContainer::FindMarkInRect(m2::AnyRectD const & rect, double & d) const
{
UserMark * mark = nullptr;
if (IsVisible())
{
FindMarkFunctor f(&mark, d, rect);
for (size_t i = 0; i < m_userMarks.size(); ++i)
{
if (m_userMarks[i]->IsAvailableForSearch() && rect.IsPointInside(m_userMarks[i]->GetPivot()))
f(m_userMarks[i].get());
}
}
return mark;
}
void UserMarkContainer::NotifyListeners()
@ -122,16 +33,10 @@ void UserMarkContainer::NotifyListeners()
df::IDCollection marks(m_createdMarks.begin(), m_createdMarks.end());
m_listeners.m_createListener(*this, marks);
}
if (m_listeners.m_updateListener != nullptr)
if (m_listeners.m_updateListener != nullptr && !m_updatedMarks.empty())
{
df::IDCollection marks;
for (auto const & mark : m_userMarks)
{
if (mark->IsDirty() && m_createdMarks.find(mark->GetId()) == m_createdMarks.end())
marks.push_back(mark->GetId());
}
if (!marks.empty())
m_listeners.m_updateListener(*this, marks);
df::IDCollection marks(m_updatedMarks.begin(), m_updatedMarks.end());
m_listeners.m_updateListener(*this, marks);
}
if (m_listeners.m_deleteListener != nullptr && !m_removedMarks.empty())
{
@ -140,75 +45,19 @@ void UserMarkContainer::NotifyListeners()
}
}
void UserMarkContainer::NotifyChanges()
{
if (!IsDirty())
return;
NotifyListeners();
df::DrapeEngineLockGuard lock(m_drapeEngine);
if (!lock)
return;
auto engine = lock.Get();
df::MarkGroupID const groupId = GenerateMarkGroupId(this);
engine->ChangeVisibilityUserMarksGroup(groupId, IsVisible() && IsDrawable());
if (GetUserPointCount() == 0 && GetUserLineCount() == 0)
{
engine->UpdateUserMarksGroup(groupId, this);
engine->ClearUserMarksGroup(groupId);
}
else if (IsVisible() && IsDrawable())
{
engine->UpdateUserMarksGroup(groupId, this);
}
engine->InvalidateUserMarks();
}
size_t UserMarkContainer::GetUserPointCount() const
{
return m_userMarks.size();
}
df::UserPointMark const * UserMarkContainer::GetUserPointMark(size_t index) const
{
return GetUserMark(index);
}
size_t UserMarkContainer::GetUserLineCount() const
{
return 0;
}
df::UserLineMark const * UserMarkContainer::GetUserLineMark(size_t index) const
{
UNUSED_VALUE(index);
ASSERT(false, ());
return nullptr;
return m_userLines.size();
}
bool UserMarkContainer::IsVisible() const
{
return m_flags[VisibleFlag];
}
bool UserMarkContainer::IsDrawable() const
{
return m_flags[DrawableFlag];
}
UserMark * UserMarkContainer::CreateUserMark(m2::PointD const & ptOrg)
{
// Push front an user mark.
SetDirty();
m_userMarks.push_front(unique_ptr<UserMark>(AllocateUserMark(ptOrg)));
m_userMarksDict.insert(make_pair(m_userMarks.front()->GetId(), m_userMarks.front().get()));
m_createdMarks.insert(m_userMarks.front()->GetId());
return m_userMarks.front().get();
return m_isVisible;
}
size_t UserMarkContainer::GetUserMarkCount() const
@ -216,32 +65,18 @@ size_t UserMarkContainer::GetUserMarkCount() const
return GetUserPointCount();
}
UserMark const * UserMarkContainer::GetUserMark(size_t index) const
{
ASSERT_LESS(index, m_userMarks.size(), ());
return m_userMarks[index].get();
}
UserMark::Type UserMarkContainer::GetType() const
{
return m_type;
}
UserMark * UserMarkContainer::GetUserMarkForEdit(size_t index)
{
SetDirty();
ASSERT_LESS(index, m_userMarks.size(), ());
return m_userMarks[index].get();
}
void UserMarkContainer::Clear()
{
SetDirty();
for (auto const & mark : m_userMarks)
for (auto const & markId : m_userMarks)
{
if (m_createdMarks.find(mark->GetId()) == m_createdMarks.end())
m_removedMarks.insert(mark->GetId());
if (m_createdMarks.find(markId) == m_createdMarks.end())
m_removedMarks.insert(markId);
}
m_createdMarks.clear();
m_userMarks.clear();
@ -252,8 +87,7 @@ void UserMarkContainer::SetIsVisible(bool isVisible)
if (IsVisible() != isVisible)
{
SetDirty();
m_flags[VisibleFlag] = isVisible;
m_flags[DrawableFlag] = isVisible;
m_isVisible = isVisible;
}
}
@ -272,33 +106,18 @@ bool UserMarkContainer::IsDirty() const
return m_isDirty;
}
void UserMarkContainer::DeleteUserMark(size_t index)
{
SetDirty();
ASSERT_LESS(index, m_userMarks.size(), ());
if (index < m_userMarks.size())
{
auto const markId = m_userMarks[index]->GetId();
auto const it = m_createdMarks.find(markId);
if (it != m_createdMarks.end())
m_createdMarks.erase(it);
else
m_removedMarks.insert(markId);
m_userMarks.erase(m_userMarks.begin() + index);
m_userMarksDict.erase(markId);
}
else
{
LOG(LWARNING, ("Trying to delete non-existing item at index", index));
}
}
void UserMarkContainer::AcceptChanges(df::MarkIDCollection & createdMarks,
void UserMarkContainer::AcceptChanges(df::MarkIDCollection & groupMarks,
df::MarkIDCollection & createdMarks,
df::MarkIDCollection & removedMarks)
{
groupMarks.Clear();
createdMarks.Clear();
removedMarks.Clear();
groupMarks.m_marksID.reserve(m_userMarks.size());
for(auto const & markId : m_userMarks)
groupMarks.m_marksID.push_back(markId);
createdMarks.m_marksID.reserve(m_createdMarks.size());
for (auto const & markId : m_createdMarks)
createdMarks.m_marksID.push_back(markId);
@ -309,5 +128,32 @@ void UserMarkContainer::AcceptChanges(df::MarkIDCollection & createdMarks,
removedMarks.m_marksID.push_back(markId);
m_removedMarks.clear();
m_updatedMarks.clear();
m_isDirty = false;
}
void UserMarkContainer::AttachUserMark(df::MarkID markId)
{
SetDirty();
m_createdMarks.insert(markId);
m_userMarks.insert(markId);
}
void UserMarkContainer::EditUserMark(df::MarkID markId)
{
SetDirty();
m_updatedMarks.insert(markId);
}
void UserMarkContainer::DetachUserMark(df::MarkID markId)
{
SetDirty();
auto const it = m_createdMarks.find(markId);
if (it != m_createdMarks.end())
m_createdMarks.erase(it);
else
m_removedMarks.insert(markId);
m_userMarks.erase(markId);
}

View file

@ -3,7 +3,6 @@
#include "map/user_mark.hpp"
#include "drape_frontend/drape_engine_safe_ptr.hpp"
#include "drape_frontend/user_marks_provider.hpp"
#include "geometry/point2d.hpp"
#include "geometry/rect2d.hpp"
@ -11,16 +10,14 @@
#include <base/macros.hpp>
#include <bitset>
#include <deque>
#include <functional>
#include <memory>
#include <set>
class UserMarkContainer : public df::UserMarksProvider
class UserMarkContainer
{
public:
using TUserMarksList = std::deque<std::unique_ptr<UserMark>>;
using MarkIDSet = std::set<df::MarkID>;
using NotifyChangesFn = std::function<void (UserMarkContainer const &, df::IDCollection const &)>;
struct Listeners
@ -41,63 +38,44 @@ public:
UserMarkContainer(UserMark::Type type,
Listeners const & listeners = Listeners());
~UserMarkContainer() override;
virtual ~UserMarkContainer();
protected:
friend class BookmarkManager;
friend class KMLParser;
void SetDrapeEngine(ref_ptr<df::DrapeEngine> engine);
UserMark const * GetUserMarkById(df::MarkID id) const;
UserMark const * GetUserMarkById(df::MarkID id, size_t & index) const;
// If not found mark on rect result is nullptr.
// If mark is found in "d" return distance from rect center.
// In multiple select choose mark with min(d).
UserMark const * FindMarkInRect(m2::AnyRectD const & rect, double & d) const;
// UserMarksProvider implementation.
size_t GetUserPointCount() const override;
df::UserPointMark const * GetUserPointMark(size_t index) const override;
size_t GetUserLineCount() const override;
df::UserLineMark const * GetUserLineMark(size_t index) const override;
bool IsDirty() const override;
size_t GetUserPointCount() const;
virtual size_t GetUserLineCount() const;
bool IsDirty() const;
// Discard isDirty flag, return id collection of removed marks since previous method call.
void AcceptChanges(df::MarkIDCollection & createdMarks,
df::MarkIDCollection & removedMarks) override;
virtual void AcceptChanges(df::MarkIDCollection & groupMarks,
df::MarkIDCollection & createdMarks,
df::MarkIDCollection & removedMarks);
void NotifyListeners();
bool IsVisible() const;
bool IsDrawable() const;
size_t GetUserMarkCount() const;
UserMark const * GetUserMark(size_t index) const;
UserMark::Type GetType() const;
UserMark * CreateUserMark(m2::PointD const & ptOrg);
UserMark * GetUserMarkForEdit(size_t index);
void DeleteUserMark(size_t index);
MarkIDSet const & GetUserMarks() const { return m_userMarks; }
void AttachUserMark(df::MarkID markId);
void EditUserMark(df::MarkID markId);
void DetachUserMark(df::MarkID markId);
void Clear();
void SetIsVisible(bool isVisible);
void Update();
void NotifyChanges();
protected:
void SetDirty();
virtual UserMark * AllocateUserMark(m2::PointD const & ptOrg) = 0;
private:
void NotifyListeners();
df::DrapeEngineSafePtr m_drapeEngine;
std::bitset<4> m_flags;
double m_layerDepth;
TUserMarksList m_userMarks;
UserMark::Type m_type;
std::set<df::MarkID> m_createdMarks;
std::set<df::MarkID> m_removedMarks;
std::map<df::MarkID, UserMark*> m_userMarksDict;
MarkIDSet m_userMarks;
MarkIDSet m_userLines;
MarkIDSet m_createdMarks;
MarkIDSet m_removedMarks;
MarkIDSet m_updatedMarks;
bool m_isVisible = true;
bool m_isDirty = false;
Listeners m_listeners;
@ -105,17 +83,3 @@ private:
DISALLOW_COPY_AND_MOVE(UserMarkContainer);
};
template<typename MarkPointClassType, UserMark::Type UserMarkType>
class SpecifiedUserMarkContainer : public UserMarkContainer
{
public:
explicit SpecifiedUserMarkContainer()
: UserMarkContainer(UserMarkType)
{}
protected:
UserMark * AllocateUserMark(m2::PointD const & ptOrg) override
{
return new MarkPointClassType(ptOrg);
}
};