ide: Xml and Json file format now shows viewer, TreeCtrl: GetOpenIds, OpenIds, Core: RegisterGlobalSerialize

git-svn-id: svn://ultimatepp.org/upp/trunk@11290 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
cxl 2017-08-05 13:59:30 +00:00
parent e43cde7556
commit fcb8e80847
15 changed files with 493 additions and 100 deletions

View file

@ -628,81 +628,88 @@ String FromSystemCharset(const String& src)
#endif
#endif
static VectorMap<String, String>& sGCfg()
{
static VectorMap<String, String> m;
return m;
}
static StaticCriticalSection sGCfgLock;
static Vector<Event<> >& sGFlush()
static VectorMap<String, String>& sGCfg()
{
static Vector<Event<> > m;
return m;
static VectorMap<String, String> h;
return h;
}
static StaticCriticalSection sGFlushLock;
static Vector<Event<>>& sGFlush()
{
static Vector<Event<>> h;
return h;
}
static VectorMap<String, Event<Stream&>>& sGSerialize()
{
static VectorMap<String, Event<Stream&>> h;
return h;
}
void RegisterGlobalConfig(const char *name)
{
INTERLOCKED_(sGCfgLock) {
ASSERT(sGCfg().Find(name) < 0);
sGCfg().Add(name);
}
Mutex::Lock __(sGCfgLock);
ASSERT(sGCfg().Find(name) < 0);
sGCfg().Add(name);
}
void RegisterGlobalSerialize(const char *name, Event<Stream&> WhenSerialize)
{
Mutex::Lock __(sGCfgLock);
RegisterGlobalConfig(name);
sGSerialize().Add(name, WhenSerialize);
}
void RegisterGlobalConfig(const char *name, Event<> WhenFlush)
{
Mutex::Lock __(sGCfgLock);
RegisterGlobalConfig(name);
INTERLOCKED_(sGFlushLock) {
sGFlush().Add(WhenFlush);
}
sGFlush().Add(WhenFlush);
}
String GetGlobalConfigData(const char *name)
{
INTERLOCKED_(sGCfgLock) {
return sGCfg().GetAdd(name);
}
return String();
Mutex::Lock __(sGCfgLock);
return sGCfg().GetAdd(name);
}
void SetGlobalConfigData(const char *name, const String& data)
{
INTERLOCKED_(sGCfgLock) {
sGCfg().GetAdd(name) = data;
}
Mutex::Lock __(sGCfgLock);
sGCfg().GetAdd(name) = data;
}
void SerializeGlobalConfigs(Stream& s)
{
INTERLOCKED_(sGFlushLock) {
for(int i = 0; i < sGFlush().GetCount(); i++)
sGFlush()[i]();
}
INTERLOCKED_(sGCfgLock) {
VectorMap<String, String>& cfg = sGCfg();
int version = 0;
s / version;
int count = cfg.GetCount();
s / count;
for(int i = 0; i < count; i++) {
String name;
if(s.IsStoring())
name = cfg.GetKey(i);
s % name;
int q = cfg.Find(name);
if(q >= 0)
s % cfg[q];
Mutex::Lock __(sGCfgLock);
for(int i = 0; i < sGFlush().GetCount(); i++)
sGFlush()[i]();
int version = 0;
s / version;
int count = sGCfg().GetCount();
s / count;
for(int i = 0; i < count; i++) {
String name;
if(s.IsStoring())
name = sGCfg().GetKey(i);
s % name;
int q = sGCfg().Find(name);
if(q >= 0) {
int w = sGSerialize().Find(name);
if(w >= 0)
sGSerialize()[w](s);
else
{
String dummy;
s % dummy;
}
s % sGCfg()[q];
}
else {
String dummy;
s % dummy;
}
s.Magic();
}
s.Magic();
}
AbortExc::AbortExc() :

View file

@ -450,8 +450,9 @@ bool LoadFromString(T& x, const String& s) {
return Load(x, ss);
}
void RegisterGlobalConfig(const char *name) init_;
void RegisterGlobalConfig(const char *name, Event<> WhenFlush) init_;
void RegisterGlobalConfig(const char *name);
void RegisterGlobalSerialize(const char *name, Event<Stream&> WhenSerialize);
void RegisterGlobalConfig(const char *name, Event<> WhenFlush);
String GetGlobalConfigData(const char *name);
void SetGlobalConfigData(const char *name, const String& data);

View file

@ -165,45 +165,42 @@ serialization of all such data with single stream.&]
[s0;0%- &]
[s5;:RegisterGlobalConfig`(const char`*`):%- [@(0.0.255) void]_[* RegisterGlobalConfig]([@(0.0.255) c
onst]_[@(0.0.255) char]_`*[*@3 name])&]
[s2; Registers name as global configuration key.&]
[s7; [%-*C@3 name]-|Key.&]
[s7; Registers name as global configuration key.&]
[s3; &]
[s4;%- &]
[s5;:RegisterGlobalConfig`(const char`*`,Callback`):%- [@(0.0.255) void]_[* RegisterGloba
lConfig]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 name], [_^Callback^ Callback]_[*@3 Whe
nFlush])&]
[s2; Registers name as global configuration key, with flush callback.&]
[s7; [%-*C@3 name]-|Key.&]
[s7; [%-*C@3 WhenFlush]-|This callback is called before storing of all
configuration keys is performed by SerializeGlobalConfigs `-
this is useful when StoreToGlobal has to be explicitly triggered
before storing configuration.&]
[s5;:Upp`:`:RegisterGlobalSerialize`(const char`*`,Upp`:`:Event`<Upp`:`:Stream`&`>`):%- [@(0.0.255) v
oid]_[* RegisterGlobalSerialize]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 name],
[_^Upp`:`:Event^ Event]<Stream[@(0.0.255) `&]>_[*@3 WhenSerialize])&]
[s2; Registers name as global configuration key. [%-*@3 WhenSerialize]
is directly used to serialize data, unlike other variants of
global config key, where data are stored / retrieved using LoadFromGlobal
/ StoreToGlobal.&]
[s3; &]
[s4;%- &]
[s5;:Upp`:`:RegisterGlobalConfig`(const char`*`,Upp`:`:Event`<`>`):%- [@(0.0.255) void]_
[* RegisterGlobalConfig]([@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 name],
[_^Upp`:`:Event^ Event]<>_[*@3 WhenFlush])&]
[s2; Registers name as global configuration key. [%-*C@3 WhenFlush]
is called before storing of all configuration keys is performed
by SerializeGlobalConfigs `- this is useful when StoreToGlobal
has to be explicitly triggered before storing configuration.&]
[s3; &]
[s4;%- &]
[s5;:LoadFromGlobal`(T`&`,const char`*`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T
][@(0.0.255) >]_[@(0.0.255) bool]_[* LoadFromGlobal]([*@4 T][@(0.0.255) `&]_[*@3 x],
[@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 name])&]
[s2; Loads [%-*@3 x] from global configuration key, using smart backup
methods provided by [^topic`:`/`/Core`/src`/SerializationUtils`$en`-us`#`:`:Load`(Callback1`<Stream`&`>`,Stream`&`)^ L
oad].&]
[s7; [*C@4 T]-|Type of serialized object.&]
[s7; [%-*C@3 x]-|Reference to serialized object.&]
[s7; [%-*C@3 name]-|Configuration key.&]
[s7; [*/ Return value]-|true indicates success.&]
[s2; Loads [%-*@3 x] from global configuration key [%-*@3 name].&]
[s3; &]
[s4;%- &]
[s5;:StoreToGlobal`(T`&`,const char`*`):%- [@(0.0.255) template]_<[@(0.0.255) class]_[*@4 T
][@(0.0.255) >]_[@(0.0.255) void]_[* StoreToGlobal]([*@4 T][@(0.0.255) `&]_[*@3 x],
[@(0.0.255) const]_[@(0.0.255) char]_`*[*@3 name])&]
[s2; Stores [@3 x] to global configuration key.&]
[s7; [*C@4 T]-|Type of serialized object.&]
[s7; [%-*C@3 x]-|Reference to serialized object.&]
[s7; [%-*C@3 name]-|Configuration key.&]
[s2; Stores [@3 x] to global configuration key [%-*C@3 name].&]
[s3; &]
[s4;%- &]
[s5;:SerializeGlobalConfigs`(Stream`&`):%- [@(0.0.255) void]_[* SerializeGlobalConfigs]([_^Stream^ S
tream][@(0.0.255) `&]_[*@3 s])&]
[s2; Serializes all global configuration data from/to single stream.&]
[s7; [%-*C@3 s]-|Stream.&]
[s2; Serializes all registered global configuration data from/to
single stream.&]
[s3; &]
[s0; ]]

View file

@ -502,6 +502,22 @@ bool TreeCtrl::IsOpen(int id) const
return item[id].isopen;
}
Vector<int> TreeCtrl::GetOpenIds() const
{
Vector<int> r;
for(int id = 0; id < item.GetCount(); id++)
if(!item[id].free && item[id].isopen)
r.Add(id);
return r;
}
void TreeCtrl::OpenIds(const Vector<int>& ids)
{
for(int id : ids)
if(IsValid(id))
Open(id);
}
void TreeCtrl::Dirty(int id)
{
// if(selectcount) SelClear(0);

View file

@ -235,6 +235,8 @@ public:
bool IsOpen(int id) const;
void Open(int id, bool open = true);
void Close(int id) { Open(id, false); }
Vector<int> GetOpenIds() const;
void OpenIds(const Vector<int>& ids);
void OpenDeep(int id, bool open = true);
void CloseDeep(int id) { OpenDeep(id, false); }

View file

@ -289,6 +289,11 @@ t]_[*@3 id])_[@(0.0.255) const]&]
[s2;%% Sets attributes.&]
[s3; &]
[s4; &]
[s5;:Upp`:`:TreeCtrl`:`:IsValid`(int`)const: [@(0.0.255) bool]_[* IsValid]([@(0.0.255) int]_
[*@3 id])_[@(0.0.255) const]&]
[s2;%% Returns true if [%-*@3 id] represents a valid node id.&]
[s3;%% &]
[s4; &]
[s5;:TreeCtrl`:`:IsOpen`(int`)const: [@(0.0.255) bool]_[* IsOpen]([@(0.0.255) int]_[*@3 id])_
[@(0.0.255) const]&]
[s2;%% Tests whether item is opened.&]
@ -304,6 +309,16 @@ all child items visible.&]
[s2;%% Same as Open(id, false).&]
[s3; &]
[s4; &]
[s5;:Upp`:`:TreeCtrl`:`:GetOpenIds`(`)const: [_^Upp`:`:Vector^ Vector]<[@(0.0.255) int]>_
[* GetOpenIds]()_[@(0.0.255) const]&]
[s2;%% Returns all open node ids.&]
[s3; &]
[s4; &]
[s5;:Upp`:`:TreeCtrl`:`:OpenIds`(const Upp`:`:Vector`<int`>`&`): [@(0.0.255) void]_[* Ope
nIds]([@(0.0.255) const]_[_^Upp`:`:Vector^ Vector]<[@(0.0.255) int]>`&_[*@3 ids])&]
[s2;%% Opens all valid [%-*@3 ids].&]
[s3;%% &]
[s4; &]
[s5;:TreeCtrl`:`:OpenDeep`(int`,bool`): [@(0.0.255) void]_[* OpenDeep]([@(0.0.255) int]_[*@3 i
d], [@(0.0.255) bool]_[*@3 open]_`=_[@(0.0.255) true])&]
[s2;%% Opens/closes item with [%-*@3 id] and all of its child items.&]

View file

@ -27,6 +27,8 @@ struct IdePngDes : IdeIconDes {
void Create(const char *filename);
};
INITIALIZE(Img)
class FileHexView : public IdeDesigner, public HexView, private LRUCache<String, int64>::Maker {
public:
virtual int Byte(int64 addr);
@ -59,10 +61,96 @@ public:
~FileHexView();
};
bool FileIsBinary(const char *path);
INITIALIZE(Img)
INITIALIZE(Qtf)
INITIALIZE(HexView)
struct IdeQtfDes : IdeDesigner, RichEditWithToolBar {
String filename;
virtual String GetFileName() const { return filename; }
virtual void Save();
virtual void SaveEditPos();
virtual void EditMenu(Bar& menu);
virtual Ctrl& DesignerCtrl() { return *this; }
virtual void Serialize(Stream& s);
bool Load(const char *filename);
void FileProperties();
void CopyId(const String& n);
typedef IdeQtfDes CLASSNAME;
IdeQtfDes() { Extended(); }
};
INITIALIZE(Qtf)
bool FileIsBinary(const char *path);
struct TreeDesPos {
Time filetime = Null;
Vector<int> openid;
int cursor = -1;
Point scroll;
void Serialize(Stream& s) { s % filetime % openid % cursor % scroll; }
void Save(Time filetime, TreeCtrl& tree);
void Restore(Time filetime, TreeCtrl& tree);
};
void Save(ArrayMap<String, TreeDesPos>& pos, const String& filename, Time filetime, TreeCtrl& tree);
void Restore(ArrayMap<String, TreeDesPos>& pos, const String& filename, Time filetime, TreeCtrl& tree);
void Serialize(Stream& s, ArrayMap<String, TreeDesPos>& pos);
struct TreeViewDes : IdeDesigner, Ctrl {
virtual String GetFileName() const { return filename; }
virtual void Save() {}
virtual void EditMenu(Bar& menu);
virtual Ctrl& DesignerCtrl() { return *this; }
virtual void RestoreEditPos();
virtual void SaveEditPos();
static ArrayMap<String, TreeDesPos> pos;
String filename;
Time filetime;
TreeCtrl tree;
FrameTop<StaticRect> errorbg;
Label error;
ParentCtrl data;
TreeViewDes();
void Error(const char *e);
bool Load(const String& txt);
virtual String GetId() = 0;
virtual void CopyPath() = 0;
virtual String Load0(const String& data) = 0;
};
INITIALIZE(TreeViewDes)
struct XmlViewDes : TreeViewDes {
virtual String GetId() { return "XML"; }
virtual void CopyPath();
virtual String Load0(const String& data);
void Load0(int parent, XmlParser& p);
};
INITIALIZE(XmlViewDes)
struct JsonViewDes : TreeViewDes {
virtual String GetId() { return "JSON"; }
virtual String Load0(const String& json);
virtual void CopyPath();
int AddNode(int parent_id, const Value& id, const String& name, const Value& v);
JsonViewDes();
};
INITIALIZE(JsonViewDes)
#endif

View file

@ -8,5 +8,8 @@ file
Png.cpp,
Img.cpp,
Qtf.cpp,
HexView.cpp;
HexView.cpp,
TreeDes.cpp,
Xml.cpp,
Json.cpp;

View file

@ -0,0 +1,105 @@
#include <ide/ide.h>
JsonViewDes::JsonViewDes()
{
tree.SetDisplay(QTFDisplay());
}
void JsonViewDes::CopyPath()
{
int id = tree.GetCursor();
String path;
while(id) {
Value k = tree.Get(id);
if(!IsNull(k)) {
if(IsNumber(k))
path = "[" + AsString(k) + "]" + path;
if(IsString(k))
path = "[" + AsCString(String(k)) + "]" + path;
}
id = tree.GetParent(id);
}
WriteClipboardText(path);
}
String JsonViewDes::Load0(const String& json)
{
String parsingError;
CParser p(json);
try {
tree.Open(AddNode(0, Null, "JSON", ParseJSON(p)));
}
catch(const CParser::Error& e) {
parsingError << e;
}
return parsingError;
}
int JsonViewDes::AddNode(int parent_id, const Value& id, const String& name, const Value& v)
{
if(IsError(v)) {
// TODO: Replace with JsonExc or something that is more accurate in this situation.
String errorText = GetErrorText(v);
errorText.Remove(0, errorText.Find(" ") + 1);
throw Exc(errorText);
}
else
if(v.Is<ValueMap>()) {
ValueMap m = v;
parent_id = tree.Add(parent_id, IdeImg::JsonStruct(), id, "[G1 [* " + name);
for(int i = 0; i < m.GetCount(); i++)
AddNode(parent_id, m.GetKey(i), "[@B \1" + String(m.GetKey(i)) + "\1:]", m.GetValue(i));
}
else
if(v.Is<ValueArray>()) {
parent_id = tree.Add(parent_id, IdeImg::JsonArray(), id, "[G1 [* " + name);
for(int i = 0; i < v.GetCount(); i++)
AddNode(parent_id, i, "[@c " + AsString(i) + ":]", v[i]);
}
else {
String qtf = "[G1 [* " + name + "]";
Image img = IdeImg::JsonNumber();
if(IsString(v)) {
img = IdeImg::JsonString();
if(IsNull(v))
qtf << "[*@g Null";
else
qtf << "[@r \1 " + AsCString(String(v));
}
else {
if(v.Is<bool>())
img = IdeImg::JsonBool();
if(IsNull(v))
qtf << "[*@g Null";
else
qtf << "\1 " + AsString(v);
}
parent_id = tree.Add(parent_id, img, id, qtf);
}
return parent_id;
}
struct JsonDesModule : public IdeModule {
virtual String GetID() { return "JsonDesModule"; }
virtual bool AcceptsFile(const char *path) {
return ToLower(GetFileExt(path)) == ".json";
}
virtual IdeDesigner *CreateDesigner(const char *path, byte) {
if(!AcceptsFile(path))
return NULL;
JsonViewDes *d = new JsonViewDes;
if(d->Load(path))
return d;
delete d;
return NULL;
}
};
INITIALIZER(JsonViewDes)
{
RegisterIdeModule(Single<JsonDesModule>());
}

View file

@ -12,7 +12,7 @@ void IdePngDes::Load(const char *_filename)
Clear();
filename = _filename;
filetime = FileGetTime(filename);
Image m = StreamRaster::LoadFileAny(filename);
Image m = StreamRaster::LoadFileAny(filename);
AddImage(filename, m, false);
SingleMode();
}

View file

@ -1,25 +1,5 @@
#include "Designers.h"
struct IdeQtfDes : IdeDesigner, RichEditWithToolBar {
String filename;
virtual String GetFileName() const { return filename; }
virtual void Save();
virtual void SaveEditPos();
virtual void EditMenu(Bar& menu);
virtual Ctrl& DesignerCtrl() { return *this; }
virtual void Serialize(Stream& s);
bool Load(const char *filename);
void FileProperties();
void CopyId(const String& n);
typedef IdeQtfDes CLASSNAME;
IdeQtfDes() { Extended(); }
};
struct IdeQtfEditPos : Moveable<IdeQtfEditPos> {
Time filetime;
RichEdit::PosInfo pos;

View file

@ -0,0 +1,93 @@
#include "Designers.h"
void TreeDesPos::Save(Time afiletime, TreeCtrl& tree)
{
filetime = afiletime;
scroll = tree.GetScroll();
cursor = tree.GetCursor();
openid = tree.GetOpenIds();
}
void TreeDesPos::Restore(Time afiletime, TreeCtrl& tree)
{
if(afiletime == filetime) {
tree.OpenIds(openid);
if(tree.IsValid(cursor))
tree.SetCursor(cursor);
tree.ScrollTo(scroll);
}
tree.SetFocus();
}
void Serialize(Stream& s, ArrayMap<String, TreeDesPos>& pos)
{
int version = 0;
s / version;
s % pos;
}
TreeViewDes::TreeViewDes()
{
tree.NoRoot();
error.SetFont(Arial(20)).SetInk(Red);
errorbg.Height(Zy(25)).Add(error.SizePos());
Add(tree.SizePos());
tree.WhenLeftDouble = [=] { CopyPath(); };
}
ArrayMap<String, TreeDesPos> TreeViewDes::pos;
bool TreeViewDes::Load(const String& fn)
{
RemoveFrame(errorbg);
tree.Clear();
filename = fn;
FileIn in(filename);
if(!in)
return false;
filetime = in.GetTime();
const int limit = 20000000;
String txt = in.Get(limit);
String parsingError = Load0(txt);
if(in.GetSize() >= limit)
MergeWith(parsingError, ", ", "file was longer than 20MB and was truncated");
if(parsingError.GetCount()) {
error = String() << "XML parsing error: " << parsingError << ".";
AddFrame(errorbg);
}
return tree.GetChildCount(0);
}
void TreeViewDes::EditMenu(Bar& menu)
{
menu.Add(tree.IsCursor(), "Copy current path to clipboard", [=] { CopyPath(); });
}
void TreeViewDes::RestoreEditPos()
{
pos.GetAdd(filename + "\n" + GetId()).Restore(filetime, tree);
}
void TreeViewDes::SaveEditPos()
{
pos.GetAdd(filename + "\n" + GetId()).Save(filetime, tree);
}
INITIALIZER(TreeViewDes)
{
RegisterGlobalSerialize("TreeViewDes", [](Stream& s) {
int version = 0;
s / version;
s % TreeViewDes::pos;
});
}

View file

@ -0,0 +1,86 @@
#include <ide/ide.h>
void XmlViewDes::CopyPath()
{
String path;
int id = tree.GetCursor();
while(id >= 0) {
String tag = tree.Get(id);
if(tag.GetCount())
path = "[" + AsCString(tag) + "]" + path;
id = tree.GetParent(id);
}
WriteClipboardText(path);
}
String XmlViewDes::Load0(const String& data) {
XmlParser p(data);
String parsingError;
try {
while(!p.IsEof())
Load0(0, p);
}
catch(const XmlError& e) {
parsingError = e;
}
if(!parsingError.GetCount() && !tree.GetChildCount(0))
parsingError = "Not found any XML tags";
return parsingError;
}
void XmlViewDes::Load0(int parent, XmlParser& p)
{
if(p.IsTag()) {
String tag = p.ReadTag();
String txt = tag;
for(int i = 0; i < p.GetAttrCount(); i++)
txt << ' ' << p.GetAttr(i) << "=\"" << p[i] << "\"";
parent = tree.Add(parent, IdeImg::XmlTag(), tag, txt);
while(!p.End()) {
if(p.IsEof())
throw XmlError("Unexpected end of text");
Load0(parent, p);
}
}
else
if(p.IsText())
tree.Add(parent, IdeImg::XmlText(), Null, NormalizeSpaces(p.ReadText()));
else
if(p.IsPI())
tree.Add(parent, IdeImg::XmlPI(), Null, NormalizeSpaces(p.ReadPI()));
else
if(p.IsDecl())
tree.Add(parent, IdeImg::XmlDecl(), Null, NormalizeSpaces(p.ReadDecl()));
else
if(p.IsComment())
tree.Add(parent, IdeImg::XmlComment(), Null, NormalizeSpaces(p.ReadComment()));
else
throw XmlError("Unexpected input");
}
struct XmlDesModule : public IdeModule {
virtual String GetID() { return "XmlDesModule"; }
virtual bool AcceptsFile(const char *path) {
return ToLower(GetFileExt(path)) == ".xml";
}
virtual IdeDesigner *CreateDesigner(const char *path, byte) {
if(!AcceptsFile(path))
return NULL;
XmlViewDes *d = new XmlViewDes;
if(d->Load(path))
return d;
delete d;
return NULL;
}
};
INITIALIZER(XmlViewDes)
{
RegisterIdeModule(Single<XmlDesModule>());
}

View file

@ -217,7 +217,7 @@ void Ide::Edit(Bar& menu)
menu.MenuSeparator();
}
else
if(editastext.Find(editfile) >= 0 && IsDesignerFile(editfile)) {
if(editastext.Find(editfile) >= 0/* && IsDesignerFile(editfile)*/) {
menu.Add(AK_DESIGNER, THISBACK(EditUsingDesigner))
.Help("Edit using the designer (not as text)");
menu.MenuSeparator();

View file

@ -458,12 +458,12 @@ void Ide::EditFile0(const String& path, byte charset, int spellcheck_comments, c
if(designer) {
editpane.Add(designer->DesignerCtrl().SizePos());
designer->DesignerCtrl().SetFocus();
designer->RestoreEditPos();
if(filetabs)
tabs.SetAddFile(editfile);
MakeTitle();
SetBar();
designer->SetFocus();
editor.SyncNavigatorShow();
return;
}