From 3ecde91bb52e11b22d9facd3ff8416fa42d228ac Mon Sep 17 00:00:00 2001 From: cxl Date: Sat, 8 Aug 2009 21:52:08 +0000 Subject: [PATCH] CtrlCore,Draw, POSIX: Fixed font metrics issue, fixed editfield frame issue, fixed PdfDraw git-svn-id: svn://ultimatepp.org/upp/trunk@1480 f0d560ea-af0d-0410-9eb7-867de7ffcac7 --- uppsrc/CtrlCore/DrawTextX11.cpp | 60 +- uppsrc/CtrlLib/ChGtk.cpp | 16 +- uppsrc/CtrlLib/EditCtrl.h | 1 + uppsrc/CtrlLib/EditField.cpp | 14 +- uppsrc/Draw/Display.cpp | 642 +++++++++--------- uppsrc/Draw/DrawText.cpp | 386 +++++------ uppsrc/Draw/Font.cpp | 758 ++++++++++----------- uppsrc/Draw/FontFc.cpp | 42 +- uppsrc/Painter/FontX11.cpp | 311 +++++---- uppsrc/PdfDraw/PdfDraw.cpp | 4 +- uppsrc/PdfDraw/init | 2 +- uppsrc/ide/Core/Host.cpp | 1129 +++++++++++++++---------------- uppsrc/usvn/SvnSync.cpp | 728 ++++++++++---------- 13 files changed, 2081 insertions(+), 2012 deletions(-) diff --git a/uppsrc/CtrlCore/DrawTextX11.cpp b/uppsrc/CtrlCore/DrawTextX11.cpp index 1f310eb95..f459a0b8b 100644 --- a/uppsrc/CtrlCore/DrawTextX11.cpp +++ b/uppsrc/CtrlCore/DrawTextX11.cpp @@ -7,11 +7,10 @@ NAMESPACE_UPP #define LTIMING(x) #define LLOG(x) -int gtk_antialias = -1; -int gtk_hinting = -1; -String gtk_hintstyle; -String gtk_rgba; - +extern int gtk_antialias; +extern int gtk_hinting; +extern String gtk_hintstyle; +extern String gtk_rgba; extern int gtk_dpi; XftFont *CreateXftFont(Font font, int angle) @@ -22,15 +21,11 @@ XftFont *CreateXftFont(Font font, int angle) Std(font); int hg = abs(font.GetHeight()); if(hg == 0) hg = 10; - int i = font.GetFace(); - if(i < 0 || i >= Font::GetFaceCount()) - i = 0; String face = font.GetFaceName(); FcPattern *p = FcPatternCreate(); FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face); FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0); FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); - FcPatternAddInteger(p, FC_DPI, gtk_dpi); FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); FcPatternAddBool(p, FC_MINSPACE, 1); if(angle) { @@ -108,6 +103,53 @@ XftFont *GetXftFont(Font fnt, int angle) return be.xftfont; } +CommonFontInfo XftGetFontInfoSys(Font font) +{ + CommonFontInfo fi; + String path; + XftFont *xftfont = GetXftFont(font, 0); + if(xftfont) { + fi.ascent = (int16)xftfont->ascent; + fi.descent = (int16)xftfont->descent; + fi.height = fi.ascent + fi.descent; + fi.lineheight = (int16)xftfont->height; + fi.external = 0; + fi.internal = 0; + fi.overhang = 0; + fi.maxwidth = (int16)xftfont->max_advance_width; + fi.avewidth = fi.maxwidth; + fi.default_char = '?'; + fi.fixedpitch = font.GetFaceInfo() & Font::FIXEDPITCH; + + char *fn = NULL; + XftPatternGetString(xftfont->pattern, XFT_FILE, 0, &fn); + if(fn && strlen(fn) < 250) + strcpy(fi.path, fn); + } + return fi; +} + +GlyphInfo XftGetGlyphInfoSys(Font font, int chr) +{ + wchar h = chr; + XGlyphInfo info; + XftTextExtents16(Xdisplay, GetXftFont(font, 0), &h, 1, &info); + GlyphInfo gi; + gi.width = info.xOff; + gi.lspc = -info.x; + gi.rspc = info.xOff - info.width + info.x; + return gi; +} + +INITBLOCK { +// extern FT_Face (*FTFaceXft)(Font fnt, String *rpath); + extern CommonFontInfo (*GetFontInfoSysXft)(Font font); + extern GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr); +// FTFaceXft = XftFTFace; + GetFontInfoSysXft = XftGetFontInfoSys; + GetGlyphInfoSysXft = XftGetGlyphInfoSys; +} + void SystemDraw::DrawTextOp(int x, int y, int angle, const wchar *text, Font font, Color ink, int n, const int *dx) { GuiLock __; diff --git a/uppsrc/CtrlLib/ChGtk.cpp b/uppsrc/CtrlLib/ChGtk.cpp index fadcce38b..d41f22f97 100644 --- a/uppsrc/CtrlLib/ChGtk.cpp +++ b/uppsrc/CtrlLib/ChGtk.cpp @@ -577,11 +577,12 @@ String GtkStyleString(const char *name) return h; } -extern int gtk_dpi; -extern int gtk_antialias; -extern int gtk_hinting; -extern String gtk_hintstyle; -extern String gtk_rgba; +int gtk_antialias = -1; +int gtk_hinting; +String gtk_hintstyle; +String gtk_rgba; + +extern void ClearFtFaceCache(); void ChHostSkin() { @@ -623,7 +624,6 @@ void ChHostSkin() String font_name = GtkStyleString("gtk-font-name"); int xdpi = Nvl(GtkStyleInt("gtk-xft-dpi"), 72 * 1024); - gtk_dpi = xdpi / 1024; gtk_antialias = Nvl(GtkStyleInt("gtk-xft-antialias"), -1); gtk_hinting = Nvl(GtkStyleInt("gtk-xft-hinting"), -1); // gtk_hintstyle = GtkStyleString("gtk-xft-hintstyle"); @@ -670,6 +670,8 @@ void ChHostSkin() Draw::SetStdFont(Font(fontname, (fontheight * xdpi + 512*72) / (1024*72)) .Bold(bold).Italic(italic)); + ClearFtFaceCache(); + ColoredOverride(CtrlsImg::Iml(), CtrlsImg::Iml()); Color fc = Blend(SColorHighlight, SColorShadow); @@ -1255,6 +1257,8 @@ void ChHostSkin() GUI_DropShadows_Write(1); GUI_AltAccessKeys_Write(1); GUI_AKD_Conservative_Write(0); + + ClearFtFaceCache(); } END_UPP_NAMESPACE diff --git a/uppsrc/CtrlLib/EditCtrl.h b/uppsrc/CtrlLib/EditCtrl.h index 87154de67..32b77bdc2 100644 --- a/uppsrc/CtrlLib/EditCtrl.h +++ b/uppsrc/CtrlLib/EditCtrl.h @@ -91,6 +91,7 @@ public: Color selected, selectedtext; Value edge[4]; bool activeedge; + int vfm; }; protected: diff --git a/uppsrc/CtrlLib/EditField.cpp b/uppsrc/CtrlLib/EditField.cpp index abbe4678a..c6ce5cba6 100644 --- a/uppsrc/CtrlLib/EditField.cpp +++ b/uppsrc/CtrlLib/EditField.cpp @@ -67,9 +67,18 @@ int TextArrayOps::GetPrevWord(int cursor) return c; } +Rect LookMargins(const Rect& r, const Value& ch) +{ + Rect m = ChMargins(ch); + int fcy = GetStdFontCy(); + if(m.top + m.bottom + fcy > r.GetHeight()) + m.top = m.bottom = max((r.GetHeight() - fcy) / 2, 0); + return m; +} + void LookFrame::FrameLayout(Rect& r) { - Rect m = ChMargins(Get()); + Rect m = LookMargins(r, Get()); r.left += m.left; r.right -= m.right; r.top += m.top; @@ -90,7 +99,7 @@ void LookFrame::FrameAddSize(Size& sz) void ActiveEdgeFrame::FrameLayout(Rect& r) { - Rect m = ChMargins(edge[0]); + Rect m = LookMargins(r, edge[0]); r.left += m.left; r.right -= m.right; r.top += m.top; @@ -135,6 +144,7 @@ CH_STYLE(EditField, Style, StyleDefault) for(int i = 0; i < 4; i++) edge[i] = CtrlsImg::EFE(); activeedge = false; + vfm = 2; } bool EditField::FrameIsEdge() diff --git a/uppsrc/Draw/Display.cpp b/uppsrc/Draw/Display.cpp index accf11296..f274d5f6e 100644 --- a/uppsrc/Draw/Display.cpp +++ b/uppsrc/Draw/Display.cpp @@ -1,321 +1,321 @@ -#include "Draw.h" - -NAMESPACE_UPP - -#define IMAGECLASS DrawImg -#define IMAGEFILE -#include - -#define LLOG(x) // RLOG(x) - -AttrText::operator Value() const -{ - return RawToValue(*this); -} - -void AttrText::Init() -{ - ink = Null; - paper = Null; - font = Null; - align = Null; -} - -AttrText::AttrText(const char *_text) -{ - text = _text; - Init(); -} - -AttrText::AttrText(const wchar *_text) -{ - text = _text; - Init(); -} - -AttrText::AttrText(const WString& _text) -{ - text = _text; - Init(); -} - -class StdDisplayClass : public Display -{ -public: - StdDisplayClass(int align = ALIGN_LEFT) : align(align) {} - - virtual void Paint0(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const; - virtual void Paint(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const; - virtual Size GetStdSize(const Value& q) const; - -private: - int align; -}; - -void Display::PaintBackground(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const -{ - if(IsType(q)) { - const AttrText& t = ValueTo(q); - if(!IsNull(t.paper)) - paper = t.paper; - } - w.DrawRect(r, paper); -} - -void Display::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const -{ - StdDisplay().Paint(w, r, q, ink, paper, style); -} - -Size Display::RatioSize(const Value& q, int cx, int cy) const { - return Size(cx, cy); -} - -Size Display::GetStdSize(const Value& q) const -{ - return Size(8, 8); -} - -void StdDisplayClass::Paint0(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword s) const { - LLOG("Display::Paint0: " << q << " ink:" << ink << " paper:" << paper); - WString txt; - Font font = StdFont(); - int a = align; - if(IsType(q)) { - const AttrText& t = ValueTo(q); - txt = t.text; - if(!IsNull(t.paper)) - paper = t.paper; - if(!IsNull(t.ink)) - ink = t.ink; - if(!IsNull(t.font)) - font = t.font; - if(!IsNull(t.align)) - a = t.align; - } - else - txt = IsString(q) ? q : StdConvert().Format(q); - int x = r.left; - Size tsz = GetTLTextSize(txt, font); - if(a == ALIGN_RIGHT) - x = r.right - tsz.cx; - if(a == ALIGN_CENTER) - x += (r.Width() - tsz.cx) / 2; - int tcy = GetTLTextHeight(txt, font); - int tt = r.top + max((r.Height() - tcy) / 2, 0); - if(tsz.cx > r.GetWidth()) { - Size isz = DrawImg::threedots().GetSize(); - int wd = r.GetWidth() - isz.cx; - w.Clip(r.left, r.top, wd, r.GetHeight()); - DrawTLText(w, x, tt, r.Width(), txt, font, ink); - w.End(); - w.DrawImage(r.left + wd, tt + font.Info().GetAscent() - isz.cy, DrawImg::threedots(), ink); - } - else - DrawTLText(w, x, tt, r.Width(), txt, font, ink); -} - -void StdDisplayClass::Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword s) const { - LLOG("Display::Paint: " << q << " ink:" << ink << " paper:" << paper); - PaintBackground(w, r, q, ink, paper, s); - Paint0(w, r, q, ink, paper, s); -} - -Size StdDisplayClass::GetStdSize(const Value& q) const -{ - Font font = StdFont(); - WString txt; - if(IsType(q)) { - const AttrText& t = ValueTo(q); - txt = t.text; - if(!IsNull(t.font)) - font = t.font; - } - else - txt = IsString(q) ? q : StdConvert().Format(q); - return GetTLTextSize(txt, font); -} - -#ifdef flagSO -Display::Display() {} -#endif - -Display::~Display() {} - -const Display& GLOBAL_V_INIT(StdDisplayClass, StdDisplay) -const Display& GLOBAL_VP_INIT(StdDisplayClass, StdCenterDisplay, (ALIGN_CENTER)) -const Display& GLOBAL_VP_INIT(StdDisplayClass, StdRightDisplay, (ALIGN_RIGHT)) - -#ifdef flagSO -ColorDisplayNull::ColorDisplayNull(String nulltext) : nulltext(nulltext) {} -ColorDisplayNull::~ColorDisplayNull() {} -#endif - -void ColorDisplayNull::Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const -{ - if(IsNull(q)) - StdDisplay().Paint(w, r, nulltext, ink, paper, style); - else - w.DrawRect(r, Color(q)); -} - -const Display& ColorDisplay() { return Single(); } - -class SizeTextDisplayCls : public Display { -public: - virtual void Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const; -}; - -void SizeTextDisplayCls::Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color, dword) const { - w.DrawText(r.left, r.top, r.Width(), (String)q, Arial(-r.Height()), ink); -} - -const Display& SizeTextDisplay() { return Single(); } - -static inline int NScale(int sz, int r) { - return sz ? sz < r ? r / sz * sz : r : 0; -} - -class CenteredImageDisplayCls : public Display { -public: - virtual void Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const - { - w.DrawRect(r, paper); - Image m = q; - Size sz = m.GetSize(); - if(!IsNull(m)) - w.DrawImage(r.left + (r.Width() - sz.cx) / 2, r.top + (r.Height() - sz.cy) / 2, m); - } - virtual Size GetStdSize(const Value& q) const - { - return Image(q).GetSize(); - } -}; - -const Display& CenteredImageDisplay() { return Single(); } - -class CenteredHighlightImageDisplayCls : public Display { -public: - virtual void Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const - { - w.DrawRect(r, paper); - Image m = q; - Size sz = m.GetSize(); - if(!IsNull(m)) - DrawHighlightImage(w, r.left + (r.Width() - sz.cx) / 2, - r.top + (r.Height() - sz.cy) / 2, m); - } - virtual Size GetStdSize(const Value& q) const - { - return Image(q).GetSize(); - } -}; - -const Display& CenteredHighlightImageDisplay() -{ - return Single(); -} - -class ImageDisplayCls : public Display { -public: - virtual void Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const - { - w.DrawRect(r, paper); - Image m = q; - if(!IsNull(m)) - w.DrawImage(r.left, r.top, Rescale(m, r.GetSize())); - } - virtual Size GetStdSize(const Value& q) const - { - return Image(q).GetSize(); - } -}; - -const Display& ImageDisplay() { return Single(); } - -class FittedImageDisplayCls : public Display { -public: - virtual void Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const - { - w.DrawRect(r, paper); - Image m = q; - if(!IsNull(m)) { - Size sz = GetFitSize(m.GetSize(), r.Size()); - Point p = r.CenterPos(sz); - w.DrawImage(p.x, p.y, m); - } - } - virtual Size GetStdSize(const Value& q) const - { - return Image(q).GetSize(); - } -}; - -const Display& FittedImageDisplay() { return Single(); } - -class DrawingDisplayCls : public Display { -public: - virtual void Paint(Draw& w, const Rect& r, const Value& q, - Color ink, Color paper, dword style) const; - virtual Size GetStdSize(const Value& q) const; - virtual Size RatioSize(const Value& q, int cx, int cy) const; -}; - -void DrawingDisplayCls::Paint(Draw& w, const Rect& r, const Value& q, - Color, Color, dword) const { - w.DrawDrawing(r, q); -} - -Size DrawingDisplayCls::GetStdSize(const Value& q) const { - return ((const Drawing&) q).GetSize(); -} - -Size DrawingDisplayCls::RatioSize(const Value& q, int cx, int cy) const { - return ((const Drawing&) q).RatioSize(cx, cy); -} - -const Display& DrawingDisplay() { return Single(); } - -Size PaintRect::GetStdSize() const { - return display ? display->GetStdSize(value) : Size(0, 0); -} - -Size PaintRect::RatioSize(int cx, int cy) const { - return display ? display->RatioSize(value, cx, cy) : Size(0, 0); -} - -void PaintRect::Paint(Draw& w, const Rect& r, - Color ink, Color paper, dword style) const { - if(display) - display->Paint(w, r, value, ink, paper, style); -} - -void PaintRect::Paint(Draw& w, int x, int y, int cx, int cy, - Color ink, Color paper, dword style) const { - Paint(w, RectC(x, y, cx, cy), ink, paper, style); -} - -PaintRect::PaintRect() { - display = NULL; -} - -PaintRect::PaintRect(const Display& _display) { - display = &_display; -} - -PaintRect::PaintRect(const Display& _display, const Value& _val) { - display = &_display; - value = _val; -} - -END_UPP_NAMESPACE +#include "Draw.h" + +NAMESPACE_UPP + +#define IMAGECLASS DrawImg +#define IMAGEFILE +#include + +#define LLOG(x) // RLOG(x) + +AttrText::operator Value() const +{ + return RawToValue(*this); +} + +void AttrText::Init() +{ + ink = Null; + paper = Null; + font = Null; + align = Null; +} + +AttrText::AttrText(const char *_text) +{ + text = _text; + Init(); +} + +AttrText::AttrText(const wchar *_text) +{ + text = _text; + Init(); +} + +AttrText::AttrText(const WString& _text) +{ + text = _text; + Init(); +} + +class StdDisplayClass : public Display +{ +public: + StdDisplayClass(int align = ALIGN_LEFT) : align(align) {} + + virtual void Paint0(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const; + virtual void Paint(Draw& draw, const Rect& rc, const Value& v, Color ink, Color paper, dword style) const; + virtual Size GetStdSize(const Value& q) const; + +private: + int align; +}; + +void Display::PaintBackground(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const +{ + if(IsType(q)) { + const AttrText& t = ValueTo(q); + if(!IsNull(t.paper)) + paper = t.paper; + } + w.DrawRect(r, paper); +} + +void Display::Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const +{ + StdDisplay().Paint(w, r, q, ink, paper, style); +} + +Size Display::RatioSize(const Value& q, int cx, int cy) const { + return Size(cx, cy); +} + +Size Display::GetStdSize(const Value& q) const +{ + return Size(8, 8); +} + +void StdDisplayClass::Paint0(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword s) const { + LLOG("Display::Paint0: " << q << " ink:" << ink << " paper:" << paper); + WString txt; + Font font = StdFont(); + int a = align; + if(IsType(q)) { + const AttrText& t = ValueTo(q); + txt = t.text; + if(!IsNull(t.paper)) + paper = t.paper; + if(!IsNull(t.ink)) + ink = t.ink; + if(!IsNull(t.font)) + font = t.font; + if(!IsNull(t.align)) + a = t.align; + } + else + txt = IsString(q) ? q : StdConvert().Format(q); + int x = r.left; + Size tsz = GetTLTextSize(txt, font); + if(a == ALIGN_RIGHT) + x = r.right - tsz.cx; + if(a == ALIGN_CENTER) + x += (r.Width() - tsz.cx) / 2; + int tcy = GetTLTextHeight(txt, font); + int tt = r.top + max((r.Height() - tcy) / 2, 0); + if(tsz.cx > r.GetWidth()) { + Size isz = DrawImg::threedots().GetSize(); + int wd = r.GetWidth() - isz.cx; + w.Clip(r.left, r.top, wd, r.GetHeight()); + DrawTLText(w, x, tt, r.Width(), txt, font, ink); + w.End(); + w.DrawImage(r.left + wd, tt + font.Info().GetAscent() - isz.cy, DrawImg::threedots(), ink); + } + else + DrawTLText(w, x, tt, r.Width(), txt, font, ink); +} + +void StdDisplayClass::Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword s) const { + LLOG("Display::Paint: " << q << " ink:" << ink << " paper:" << paper); + PaintBackground(w, r, q, ink, paper, s); + Paint0(w, r, q, ink, paper, s); +} + +Size StdDisplayClass::GetStdSize(const Value& q) const +{ + Font font = StdFont(); + WString txt; + if(IsType(q)) { + const AttrText& t = ValueTo(q); + txt = t.text; + if(!IsNull(t.font)) + font = t.font; + } + else + txt = IsString(q) ? q : StdConvert().Format(q); + return GetTLTextSize(txt, font); +} + +#ifdef flagSO +Display::Display() {} +#endif + +Display::~Display() {} + +const Display& GLOBAL_V_INIT(StdDisplayClass, StdDisplay) +const Display& GLOBAL_VP_INIT(StdDisplayClass, StdCenterDisplay, (ALIGN_CENTER)) +const Display& GLOBAL_VP_INIT(StdDisplayClass, StdRightDisplay, (ALIGN_RIGHT)) + +#ifdef flagSO +ColorDisplayNull::ColorDisplayNull(String nulltext) : nulltext(nulltext) {} +ColorDisplayNull::~ColorDisplayNull() {} +#endif + +void ColorDisplayNull::Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const +{ + if(IsNull(q)) + StdDisplay().Paint(w, r, nulltext, ink, paper, style); + else + w.DrawRect(r, Color(q)); +} + +const Display& ColorDisplay() { return Single(); } + +class SizeTextDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const; +}; + +void SizeTextDisplayCls::Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color, dword) const { + w.DrawText(r.left, r.top, r.Width(), (String)q, Arial(-r.Height()), ink); +} + +const Display& SizeTextDisplay() { return Single(); } + +static inline int NScale(int sz, int r) { + return sz ? sz < r ? r / sz * sz : r : 0; +} + +class CenteredImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + Size sz = m.GetSize(); + if(!IsNull(m)) + w.DrawImage(r.left + (r.Width() - sz.cx) / 2, r.top + (r.Height() - sz.cy) / 2, m); + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& CenteredImageDisplay() { return Single(); } + +class CenteredHighlightImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + Size sz = m.GetSize(); + if(!IsNull(m)) + DrawHighlightImage(w, r.left + (r.Width() - sz.cx) / 2, + r.top + (r.Height() - sz.cy) / 2, m); + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& CenteredHighlightImageDisplay() +{ + return Single(); +} + +class ImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + if(!IsNull(m)) + w.DrawImage(r.left, r.top, Rescale(m, r.GetSize())); + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& ImageDisplay() { return Single(); } + +class FittedImageDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const + { + w.DrawRect(r, paper); + Image m = q; + if(!IsNull(m)) { + Size sz = GetFitSize(m.GetSize(), r.Size()); + Point p = r.CenterPos(sz); + w.DrawImage(p.x, p.y, m); + } + } + virtual Size GetStdSize(const Value& q) const + { + return Image(q).GetSize(); + } +}; + +const Display& FittedImageDisplay() { return Single(); } + +class DrawingDisplayCls : public Display { +public: + virtual void Paint(Draw& w, const Rect& r, const Value& q, + Color ink, Color paper, dword style) const; + virtual Size GetStdSize(const Value& q) const; + virtual Size RatioSize(const Value& q, int cx, int cy) const; +}; + +void DrawingDisplayCls::Paint(Draw& w, const Rect& r, const Value& q, + Color, Color, dword) const { + w.DrawDrawing(r, q); +} + +Size DrawingDisplayCls::GetStdSize(const Value& q) const { + return ((const Drawing&) q).GetSize(); +} + +Size DrawingDisplayCls::RatioSize(const Value& q, int cx, int cy) const { + return ((const Drawing&) q).RatioSize(cx, cy); +} + +const Display& DrawingDisplay() { return Single(); } + +Size PaintRect::GetStdSize() const { + return display ? display->GetStdSize(value) : Size(0, 0); +} + +Size PaintRect::RatioSize(int cx, int cy) const { + return display ? display->RatioSize(value, cx, cy) : Size(0, 0); +} + +void PaintRect::Paint(Draw& w, const Rect& r, + Color ink, Color paper, dword style) const { + if(display) + display->Paint(w, r, value, ink, paper, style); +} + +void PaintRect::Paint(Draw& w, int x, int y, int cx, int cy, + Color ink, Color paper, dword style) const { + Paint(w, RectC(x, y, cx, cy), ink, paper, style); +} + +PaintRect::PaintRect() { + display = NULL; +} + +PaintRect::PaintRect(const Display& _display) { + display = &_display; +} + +PaintRect::PaintRect(const Display& _display, const Value& _val) { + display = &_display; + value = _val; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/DrawText.cpp b/uppsrc/Draw/DrawText.cpp index 023b0e46c..f9b9fe67b 100644 --- a/uppsrc/Draw/DrawText.cpp +++ b/uppsrc/Draw/DrawText.cpp @@ -1,193 +1,193 @@ -#include "Draw.h" - -NAMESPACE_UPP - - -#define LLOG(x) // LOG(x) -#define LTIMING(x) // TIMING(x) - -WString TextUnicode(const char *s, int n, byte cs, Font font) -{ - if(n < 0) - n = (int)strlen(s); -#ifdef PLATFORM_WIN32 - if(font.GetFace() == Font::SYMBOL) { - WStringBuffer b(n); - wchar *t = b; - while(n > 0) { - *t++ = *s++; - n--; - } - return b; - } -#endif - return ToUnicode(s, n, cs); -} - -void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font, - Color ink, int n, const int *dx) -{ - if(IsNull(ink)) return; - if(n < 0) - n = wstrlen(text); - Std(font); - double sina; - double cosa; - int d = 0; - if(angle) - Draw::SinCos(angle, sina, cosa); - for(int i = 0; i < n; i++) { - wchar chr = text[i]; - GlyphInfo gi = GetGlyphInfo(font, chr); - if(gi.IsNormal()) - if(angle) - DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &chr, font, ink, 1, NULL); - else { - int c = 1; - int dd = 0; - while(c < n) { - GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]); - if(!gi2.IsNormal()) - break; - dd += dx ? dx[c] : gi.width; - c++; - gi = gi2; - } - DrawTextOp(x + d, y, 0, text + i, font, ink, c, dx); - d += dd; - i += c - 1; - if(dx) - dx += c - 1; - } - else - if(gi.IsReplaced()) { - Font fnt = font; - fnt.Face(gi.lspc); - fnt.Height(gi.rspc); - if(angle) - DrawTextOp(int(x + cosa * d), int(y - sina * (font.GetAscent() - fnt.GetAscent() + d)), - angle, &chr, fnt, ink, 1, NULL); - else - DrawTextOp(x + d, y + font.GetAscent() - fnt.GetAscent(), 0, &chr, fnt, ink, 1, NULL); - GlyphMetrics(gi, font, chr); - } - else - if(gi.IsComposed()) { - ComposedGlyph cg; - Compose(font, chr, cg); - if(angle) { - DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &cg.basic_char, font, ink, 1, NULL); - DrawTextOp(int(x + cosa * (d + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + d)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); - } - else { - DrawTextOp(x + d, y, 0, &cg.basic_char, font, ink, 1, NULL); - DrawTextOp(x + cg.mark_pos.x + d, y + cg.mark_pos.y, 0, &cg.mark_char, cg.mark_font, ink, 1, NULL); - } - GlyphMetrics(gi, font, chr); - } - d += dx ? *dx++ : gi.width; - } -} - -// ---------------------------- - -void Draw::DrawText(int x, int y, const wchar *text, Font font, - Color ink, int n, const int *dx) -{ - DrawText(x, y, 0, text, font, ink, n, dx); -} - -// --------------------------- - -void Draw::DrawText(int x, int y, int angle, const WString& text, Font font, - Color ink, const int *dx) -{ - DrawText(x, y, angle, ~text, font, ink, text.GetLength(), dx); -} - -void Draw::DrawText(int x, int y, const WString& text, Font font, Color ink, const int *dx) -{ - DrawText(x, y, 0, text, font, ink, dx); -} - -// --------------------------- - -void Draw::DrawText(int x, int y, int angle, const char *text, byte charset, Font font, - Color ink, int n, const int *dx) -{ - DrawText(x, y, angle, TextUnicode(text, n, charset, font), font, ink, dx); -} - -void Draw::DrawText(int x, int y, const char *text, byte charset, Font font, - Color ink, int n, const int *dx) -{ - DrawText(x, y, 0, text, charset, font, ink, n, dx); -} - -// --------------------------- - -void Draw::DrawText(int x, int y, int angle, const char *text, - Font font, Color ink, int n, const int *dx) -{ - DrawText(x, y, angle, text, CHARSET_DEFAULT, font, ink, n, dx); -} - -void Draw::DrawText(int x, int y, const char *text, Font font, - Color ink, int n, const int *dx) -{ - DrawText(x, y, text, CHARSET_DEFAULT, font, ink, n, dx); -} - -// --------------------------- - -void Draw::DrawText(int x, int y, int angle, const String& text, Font font, - Color ink, const int *dx) -{ - DrawText(x, y, angle, text, font, ink, text.GetLength(), dx); -} - -void Draw::DrawText(int x, int y, const String& text, Font font, Color ink, const int *dx) -{ - WString h = TextUnicode(text, text.GetLength(), CHARSET_DEFAULT, font); - DrawText(x, y, h, font, ink, h.GetLength(), dx); -} - -// -------------------------- - -Size GetTextSize(const wchar *text, Font font, int n) -{ - FontInfo fi = font.Info(); - if(n < 0) - n = wstrlen(text); - Size sz; - sz.cx = 0; - const wchar *wtext = (const wchar *)text; - while(n > 0) { - sz.cx += fi[*wtext++]; - n--; - } - sz.cy = fi.GetHeight(); - return sz; -} - -Size GetTextSize(const WString& text, Font font) -{ - return GetTextSize(text, font, text.GetLength()); -} - -Size GetTextSize(const char *text, byte charset, Font font, int n) -{ - return GetTextSize(TextUnicode(text, n, charset, font), font); -} - -Size GetTextSize(const char *text, Font font, int n) -{ - return GetTextSize(text, CHARSET_DEFAULT, font, n); -} - -Size GetTextSize(const String& text, Font font) -{ - return GetTextSize(text, font, text.GetLength()); -} - -END_UPP_NAMESPACE +#include "Draw.h" + +NAMESPACE_UPP + + +#define LLOG(x) // LOG(x) +#define LTIMING(x) // TIMING(x) + +WString TextUnicode(const char *s, int n, byte cs, Font font) +{ + if(n < 0) + n = (int)strlen(s); +#ifdef PLATFORM_WIN32 + if(font.GetFace() == Font::SYMBOL) { + WStringBuffer b(n); + wchar *t = b; + while(n > 0) { + *t++ = *s++; + n--; + } + return b; + } +#endif + return ToUnicode(s, n, cs); +} + +void Draw::DrawText(int x, int y, int angle, const wchar *text, Font font, + Color ink, int n, const int *dx) +{ + if(IsNull(ink)) return; + if(n < 0) + n = wstrlen(text); + Std(font); + double sina; + double cosa; + int d = 0; + if(angle) + Draw::SinCos(angle, sina, cosa); + for(int i = 0; i < n; i++) { + wchar chr = text[i]; + GlyphInfo gi = GetGlyphInfo(font, chr); + if(gi.IsNormal()) + if(angle) + DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &chr, font, ink, 1, NULL); + else { + int c = 1; + int dd = 0; + while(c < n) { + GlyphInfo gi2 = GetGlyphInfo(font, text[i + c]); + if(!gi2.IsNormal()) + break; + dd += dx ? dx[c] : gi.width; + c++; + gi = gi2; + } + DrawTextOp(x + d, y, 0, text + i, font, ink, c, dx); + d += dd; + i += c - 1; + if(dx) + dx += c - 1; + } + else + if(gi.IsReplaced()) { + Font fnt = font; + fnt.Face(gi.lspc); + fnt.Height(gi.rspc); + if(angle) + DrawTextOp(int(x + cosa * d), int(y - sina * (font.GetAscent() - fnt.GetAscent() + d)), + angle, &chr, fnt, ink, 1, NULL); + else + DrawTextOp(x + d, y + font.GetAscent() - fnt.GetAscent(), 0, &chr, fnt, ink, 1, NULL); + GlyphMetrics(gi, font, chr); + } + else + if(gi.IsComposed()) { + ComposedGlyph cg; + Compose(font, chr, cg); + if(angle) { + DrawTextOp(int(x + cosa * d), int(y - sina * d), angle, &cg.basic_char, font, ink, 1, NULL); + DrawTextOp(int(x + cosa * (d + cg.mark_pos.x)), int(y - sina * (cg.mark_pos.y + d)), angle, &cg.mark_char, cg.mark_font, ink, 1, NULL); + } + else { + DrawTextOp(x + d, y, 0, &cg.basic_char, font, ink, 1, NULL); + DrawTextOp(x + cg.mark_pos.x + d, y + cg.mark_pos.y, 0, &cg.mark_char, cg.mark_font, ink, 1, NULL); + } + GlyphMetrics(gi, font, chr); + } + d += dx ? *dx++ : gi.width; + } +} + +// ---------------------------- + +void Draw::DrawText(int x, int y, const wchar *text, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, 0, text, font, ink, n, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const WString& text, Font font, + Color ink, const int *dx) +{ + DrawText(x, y, angle, ~text, font, ink, text.GetLength(), dx); +} + +void Draw::DrawText(int x, int y, const WString& text, Font font, Color ink, const int *dx) +{ + DrawText(x, y, 0, text, font, ink, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const char *text, byte charset, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, angle, TextUnicode(text, n, charset, font), font, ink, dx); +} + +void Draw::DrawText(int x, int y, const char *text, byte charset, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, 0, text, charset, font, ink, n, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const char *text, + Font font, Color ink, int n, const int *dx) +{ + DrawText(x, y, angle, text, CHARSET_DEFAULT, font, ink, n, dx); +} + +void Draw::DrawText(int x, int y, const char *text, Font font, + Color ink, int n, const int *dx) +{ + DrawText(x, y, text, CHARSET_DEFAULT, font, ink, n, dx); +} + +// --------------------------- + +void Draw::DrawText(int x, int y, int angle, const String& text, Font font, + Color ink, const int *dx) +{ + DrawText(x, y, angle, text, font, ink, text.GetLength(), dx); +} + +void Draw::DrawText(int x, int y, const String& text, Font font, Color ink, const int *dx) +{ + WString h = TextUnicode(text, text.GetLength(), CHARSET_DEFAULT, font); + DrawText(x, y, h, font, ink, h.GetLength(), dx); +} + +// -------------------------- + +Size GetTextSize(const wchar *text, Font font, int n) +{ + FontInfo fi = font.Info(); + if(n < 0) + n = wstrlen(text); + Size sz; + sz.cx = 0; + const wchar *wtext = (const wchar *)text; + while(n > 0) { + sz.cx += fi[*wtext++]; + n--; + } + sz.cy = fi.GetHeight(); + return sz; +} + +Size GetTextSize(const WString& text, Font font) +{ + return GetTextSize(text, font, text.GetLength()); +} + +Size GetTextSize(const char *text, byte charset, Font font, int n) +{ + return GetTextSize(TextUnicode(text, n, charset, font), font); +} + +Size GetTextSize(const char *text, Font font, int n) +{ + return GetTextSize(text, CHARSET_DEFAULT, font, n); +} + +Size GetTextSize(const String& text, Font font) +{ + return GetTextSize(text, font, text.GetLength()); +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/Font.cpp b/uppsrc/Draw/Font.cpp index 673bbaca8..bf82e1aee 100644 --- a/uppsrc/Draw/Font.cpp +++ b/uppsrc/Draw/Font.cpp @@ -1,379 +1,379 @@ -#include "Draw.h" - -#define LLOG(x) - -NAMESPACE_UPP - -CommonFontInfo GetFontInfoSys(Font font); -GlyphInfo GetGlyphInfoSys(Font font, int chr); -void GetStdFontSys(String& name, int& height); -Vector GetAllFacesSys(); - -bool Replace(Font fnt, int chr, Font& rfnt); - -void Std(Font& font) -{ - if(IsNull(font)) - font = StdFont(); - if(font.GetFace() == 0) - font.Face(GetStdFont().GetFace()); - if(font.GetHeight() == 0) - font.Height(GetStdFont().GetHeight()); -} - -Size Font::StdFontSize; -Font Font::AStdFont; - -INITBLOCK { - RichValue::Register(); -} - -const Vector& Font::List() -{ - static Vector *q; - ONCELOCK { - static Vector x; - x = GetAllFacesSys(); - q = &x; - } - return *q; -} - -void sInitFonts() -{ - Font::List(); - GetStdFont(); -} - -INITBLOCK { - sInitFonts(); -} - -int Font::GetFaceCount() -{ - return List().GetCount(); -} - -String Font::GetFaceName(int index) -{ - if(index == 0) - return "STDFONT"; - const Vector& l = List(); - if(index >= 0 && index < l.GetCount()) - return l[index].name; - return Null; -} - -dword Font::GetFaceInfo(int index) -{ - const Vector& l = List(); - if(index >= 0 && index < l.GetCount()) - return l[index].info; - return 0; -} - -int FontFilter(int c) -{ - return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0; -} - -int Font::FindFaceNameIndex(const String& name) { - if(name == "STDFONT") - return 0; - for(int i = 1; i < GetFaceCount(); i++) - if(GetFaceName(i) == name) - return i; - String n = Filter(name, FontFilter); - for(int i = 1; i < GetFaceCount(); i++) - if(Filter(GetFaceName(i), FontFilter) == n) - return i; - return 0; -} - -void Font::SyncStdFont() -{ - DrawLock __; - StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetCy()); -} - -void Font::SetStdFont(Font font) -{ - DrawLock __; - InitStdFont(); - AStdFont = font; - SyncStdFont(); -} - -void Font::InitStdFont() -{ - ONCELOCK { - DrawLock __; - List(); - AStdFont = Arial(12); - String name; - int height = 0; - GetStdFontSys(name, height); - int q = FindFaceNameIndex(name); - if(q > 0) { - AStdFont = Font(q, max(height, 1)); - SyncStdFont(); - } - } -} - -Font Font::GetStdFont() -{ - InitStdFont(); - return AStdFont; -} - -Size Font::GetStdFontSize() -{ - InitStdFont(); - return StdFontSize; -} - -Font StdFont() -{ - return Font(0, 0); -} - -int Font::GetHeight() const -{ - return v.height || v.face ? v.height : GetStdFont().GetHeight(); -} - -String Font::GetFaceName() const { - if(IsNull()) return String(); - if(GetFace() == 0) - return "STDFONT"; - return GetFaceName(GetFace()); -} - -dword Font::GetFaceInfo() const { - if(IsNull()) return 0; - return GetFaceInfo(GetFace()); -} - -Font& Font::FaceName(const String& name) { - int n = FindFaceNameIndex(name); - Face(n < 0 ? 0xffff : n); - return *this; -} - -void Font::Serialize(Stream& s) { - int version = 1; - s / version; - if(version >= 1) { - enum { - OLD_STDFONT, OLD_SCREEN_SERIF, OLD_SCREEN_SANS, OLD_SCREEN_FIXED, - OLD_ROMAN, - OLD_ARIAL, - OLD_COURIER, - }; - int f = GetFace(); - if(f > COURIER) - f = -1; - s / f; - String name; - if(f == OLD_ROMAN) - f = ROMAN; - if(f == OLD_ARIAL) - f = ARIAL; - if(f == OLD_COURIER) - f = COURIER; - if(f < 0) { - name = GetFaceName(); - s % name; - } - if(s.IsLoading()) - if(f >= 0) - Face(f); - else - FaceName(name); - } - else { - String name = GetFaceName(); - s % name; - if(s.IsLoading()) { - FaceName(name); - if(IsNull()) - Face(COURIER); - } - } - s % v.flags % v.height % v.width; -} - -template<> -String AsString(const Font& f) { - if(IsNull(f)) return ""; - String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight()); - if(f.IsBold()) - s += " Bold"; - if(f.IsItalic()) - s += " Italic"; - if(f.IsUnderline()) - s += " Underline"; - if(f.IsStrikeout()) - s += " Strikeout"; - return s + '>'; -} - -struct CharEntry { - int64 font; - GlyphInfo info; - word chr; -}; - -CharEntry fc_cache_global[4093]; - -bool IsNormal(Font font, int chr) -{ - DrawLock __; - CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093]; - if(e.font == font.AsInt64() || e.chr == chr) - return e.info.IsNormal(); - return GetGlyphInfoSys(font, chr).IsNormal(); -} - -CharEntry GetGlyphEntry(Font font, int chr, unsigned hash) -{ - DrawLock __; - CharEntry& e = fc_cache_global[hash % 4093]; - if(e.font != font.AsInt64() || e.chr != chr) { - e.font = font.AsInt64(); - e.chr = chr; - e.info = GetGlyphInfoSys(font, chr); - if(!e.info.IsNormal()) { - ComposedGlyph cg; - Font rfnt; - if(Compose(font, chr, cg)) { - e.info.lspc = -1; - e.info.rspc = cg.basic_char; - } - else - if(Replace(font, chr, rfnt)) { - e.info.lspc = rfnt.GetFace(); - e.info.rspc = rfnt.GetHeight(); - } - else - e.info.lspc = -2; - } - } - return e; -} - -thread__ CharEntry fc_cache[512]; - -GlyphInfo GetGlyphInfo(Font font, int chr) -{ - Std(font); - unsigned hash = CombineHash(font.GetHashValue(), chr); - CharEntry& e = fc_cache[hash & 511]; - if(e.font != font.AsInt64() || e.chr != chr) - e = GetGlyphEntry(font, chr, hash); - return e.info; -} - -bool Font::IsNormal(int ch) const -{ - return GetGlyphInfo(*this, ch).IsNormal(); -} - -bool Font::IsComposed(int ch) const -{ - return GetGlyphInfo(*this, ch).IsComposed(); -} - -bool Font::IsReplaced(int ch) const -{ - return GetGlyphInfo(*this, ch).IsReplaced(); -} - -bool Font::IsMissing(int ch) const -{ - return GetGlyphInfo(*this, ch).IsMissing(); -} - -int Font::HasChar(int ch) const -{ - return !GetGlyphInfo(*this, ch).IsMissing(); -} - -void GlyphMetrics(GlyphInfo& f, Font font, int chr) -{ - if(f.IsReplaced()) - f = GetGlyphInfo(font().Face(f.lspc).Height(f.rspc), chr); - if(f.IsComposed()) { - f = GetGlyphInfo(font, f.rspc); - if(f.IsComposedLM()) - f.rspc += f.width / 2; - } -} - -GlyphInfo GetGlyphMetrics(Font font, int chr) -{ - GlyphInfo f = GetGlyphInfo(font, chr); - if(f.IsMissing()) - f = GetGlyphInfo(font, '?'); - GlyphMetrics(f, font, chr); - return f; -} - -struct FontEntry { - CommonFontInfo info; - int64 font; -}; - -thread__ FontEntry fi_cache[64]; - -const CommonFontInfo& GetFontInfo(Font font) -{ - Std(font); - unsigned hash = font.GetHashValue() & 63; - FontEntry& e = fi_cache[hash]; - if(e.font != font.AsInt64()) { - DrawLock __; - e.font = font.AsInt64(); - e.info = GetFontInfoSys(font); - } - return e.info; -} - -int Font::GetWidth(int c) const { - return GetGlyphMetrics(*this, c).width; -} - -int Font::GetLeftSpace(int c) const { - return GetGlyphMetrics(*this, c).lspc; -} - -int Font::GetRightSpace(int c) const { - return GetGlyphMetrics(*this, c).rspc; -} - -thread__ int64 lastFiFont = INT_MIN; -thread__ CommonFontInfo lastFontInfo; -thread__ int64 lastStdFont = INT_MIN; - -const CommonFontInfo& Font::Fi() const -{ - if(lastStdFont != AStdFont.AsInt64()) { - lastFiFont = INT_MIN; - lastStdFont = AStdFont.AsInt64(); - } - if(AsInt64() == lastFiFont) - return lastFontInfo; - lastFontInfo = GetFontInfo(*this); - lastFiFont = AsInt64(); - return lastFontInfo; -} - -FontInfo Font::Info() const -{ - FontInfo h; - h.font = *this; - return h; -} - -END_UPP_NAMESPACE +#include "Draw.h" + +#define LLOG(x) + +NAMESPACE_UPP + +CommonFontInfo GetFontInfoSys(Font font); +GlyphInfo GetGlyphInfoSys(Font font, int chr); +void GetStdFontSys(String& name, int& height); +Vector GetAllFacesSys(); + +bool Replace(Font fnt, int chr, Font& rfnt); + +void Std(Font& font) +{ + if(IsNull(font)) + font = StdFont(); + if(font.GetFace() == 0) + font.Face(GetStdFont().GetFace()); + if(font.GetHeight() == 0) + font.Height(GetStdFont().GetHeight()); +} + +Size Font::StdFontSize; +Font Font::AStdFont; + +INITBLOCK { + RichValue::Register(); +} + +const Vector& Font::List() +{ + static Vector *q; + ONCELOCK { + static Vector x; + x = GetAllFacesSys(); + q = &x; + } + return *q; +} + +void sInitFonts() +{ + Font::List(); + GetStdFont(); +} + +INITBLOCK { + sInitFonts(); +} + +int Font::GetFaceCount() +{ + return List().GetCount(); +} + +String Font::GetFaceName(int index) +{ + if(index == 0) + return "STDFONT"; + const Vector& l = List(); + if(index >= 0 && index < l.GetCount()) + return l[index].name; + return Null; +} + +dword Font::GetFaceInfo(int index) +{ + const Vector& l = List(); + if(index >= 0 && index < l.GetCount()) + return l[index].info; + return 0; +} + +int FontFilter(int c) +{ + return c >= 'a' && c <= 'z' || c >= '0' && c <= '9' ? c : c >= 'A' && c <= 'Z' ? ToLower(c) : 0; +} + +int Font::FindFaceNameIndex(const String& name) { + if(name == "STDFONT") + return 0; + for(int i = 1; i < GetFaceCount(); i++) + if(GetFaceName(i) == name) + return i; + String n = Filter(name, FontFilter); + for(int i = 1; i < GetFaceCount(); i++) + if(Filter(GetFaceName(i), FontFilter) == n) + return i; + return 0; +} + +void Font::SyncStdFont() +{ + DrawLock __; + StdFontSize = Size(AStdFont.GetAveWidth(), AStdFont().Bold().GetCy()); +} + +void Font::SetStdFont(Font font) +{ + DrawLock __; + InitStdFont(); + AStdFont = font; + SyncStdFont(); +} + +void Font::InitStdFont() +{ + ONCELOCK { + DrawLock __; + List(); + AStdFont = Arial(12); + String name; + int height = 0; + GetStdFontSys(name, height); + int q = FindFaceNameIndex(name); + if(q > 0) { + AStdFont = Font(q, max(height, 1)); + SyncStdFont(); + } + } +} + +Font Font::GetStdFont() +{ + InitStdFont(); + return AStdFont; +} + +Size Font::GetStdFontSize() +{ + InitStdFont(); + return StdFontSize; +} + +Font StdFont() +{ + return Font(0, 0); +} + +int Font::GetHeight() const +{ + return v.height || v.face ? v.height : GetStdFont().GetHeight(); +} + +String Font::GetFaceName() const { + if(IsNull()) return String(); + if(GetFace() == 0) + return "STDFONT"; + return GetFaceName(GetFace()); +} + +dword Font::GetFaceInfo() const { + if(IsNull()) return 0; + return GetFaceInfo(GetFace()); +} + +Font& Font::FaceName(const String& name) { + int n = FindFaceNameIndex(name); + Face(n < 0 ? 0xffff : n); + return *this; +} + +void Font::Serialize(Stream& s) { + int version = 1; + s / version; + if(version >= 1) { + enum { + OLD_STDFONT, OLD_SCREEN_SERIF, OLD_SCREEN_SANS, OLD_SCREEN_FIXED, + OLD_ROMAN, + OLD_ARIAL, + OLD_COURIER, + }; + int f = GetFace(); + if(f > COURIER) + f = -1; + s / f; + String name; + if(f == OLD_ROMAN) + f = ROMAN; + if(f == OLD_ARIAL) + f = ARIAL; + if(f == OLD_COURIER) + f = COURIER; + if(f < 0) { + name = GetFaceName(); + s % name; + } + if(s.IsLoading()) + if(f >= 0) + Face(f); + else + FaceName(name); + } + else { + String name = GetFaceName(); + s % name; + if(s.IsLoading()) { + FaceName(name); + if(IsNull()) + Face(COURIER); + } + } + s % v.flags % v.height % v.width; +} + +template<> +String AsString(const Font& f) { + if(IsNull(f)) return ""; + String s = "<" + f.GetFaceName() + Format(":%d", f.GetHeight()); + if(f.IsBold()) + s += " Bold"; + if(f.IsItalic()) + s += " Italic"; + if(f.IsUnderline()) + s += " Underline"; + if(f.IsStrikeout()) + s += " Strikeout"; + return s + '>'; +} + +struct CharEntry { + int64 font; + GlyphInfo info; + word chr; +}; + +CharEntry fc_cache_global[4093]; + +bool IsNormal(Font font, int chr) +{ + DrawLock __; + CharEntry& e = fc_cache_global[CombineHash(font.GetHashValue(), chr) % 4093]; + if(e.font == font.AsInt64() || e.chr == chr) + return e.info.IsNormal(); + return GetGlyphInfoSys(font, chr).IsNormal(); +} + +CharEntry GetGlyphEntry(Font font, int chr, unsigned hash) +{ + DrawLock __; + CharEntry& e = fc_cache_global[hash % 4093]; + if(e.font != font.AsInt64() || e.chr != chr) { + e.font = font.AsInt64(); + e.chr = chr; + e.info = GetGlyphInfoSys(font, chr); + if(!e.info.IsNormal()) { + ComposedGlyph cg; + Font rfnt; + if(Compose(font, chr, cg)) { + e.info.lspc = -1; + e.info.rspc = cg.basic_char; + } + else + if(Replace(font, chr, rfnt)) { + e.info.lspc = rfnt.GetFace(); + e.info.rspc = rfnt.GetHeight(); + } + else + e.info.lspc = -2; + } + } + return e; +} + +thread__ CharEntry fc_cache[512]; + +GlyphInfo GetGlyphInfo(Font font, int chr) +{ + Std(font); + unsigned hash = CombineHash(font.GetHashValue(), chr); + CharEntry& e = fc_cache[hash & 511]; + if(e.font != font.AsInt64() || e.chr != chr) + e = GetGlyphEntry(font, chr, hash); + return e.info; +} + +bool Font::IsNormal(int ch) const +{ + return GetGlyphInfo(*this, ch).IsNormal(); +} + +bool Font::IsComposed(int ch) const +{ + return GetGlyphInfo(*this, ch).IsComposed(); +} + +bool Font::IsReplaced(int ch) const +{ + return GetGlyphInfo(*this, ch).IsReplaced(); +} + +bool Font::IsMissing(int ch) const +{ + return GetGlyphInfo(*this, ch).IsMissing(); +} + +int Font::HasChar(int ch) const +{ + return !GetGlyphInfo(*this, ch).IsMissing(); +} + +void GlyphMetrics(GlyphInfo& f, Font font, int chr) +{ + if(f.IsReplaced()) + f = GetGlyphInfo(font().Face(f.lspc).Height(f.rspc), chr); + if(f.IsComposed()) { + f = GetGlyphInfo(font, f.rspc); + if(f.IsComposedLM()) + f.rspc += f.width / 2; + } +} + +GlyphInfo GetGlyphMetrics(Font font, int chr) +{ + GlyphInfo f = GetGlyphInfo(font, chr); + if(f.IsMissing()) + f = GetGlyphInfo(font, '?'); + GlyphMetrics(f, font, chr); + return f; +} + +struct FontEntry { + CommonFontInfo info; + int64 font; +}; + +thread__ FontEntry fi_cache[64]; + +const CommonFontInfo& GetFontInfo(Font font) +{ + Std(font); + unsigned hash = font.GetHashValue() & 63; + FontEntry& e = fi_cache[hash]; + if(e.font != font.AsInt64()) { + DrawLock __; + e.font = font.AsInt64(); + e.info = GetFontInfoSys(font); + } + return e.info; +} + +int Font::GetWidth(int c) const { + return GetGlyphMetrics(*this, c).width; +} + +int Font::GetLeftSpace(int c) const { + return GetGlyphMetrics(*this, c).lspc; +} + +int Font::GetRightSpace(int c) const { + return GetGlyphMetrics(*this, c).rspc; +} + +thread__ int64 lastFiFont = INT_MIN; +thread__ CommonFontInfo lastFontInfo; +thread__ int64 lastStdFont = INT_MIN; + +const CommonFontInfo& Font::Fi() const +{ + if(lastStdFont != AStdFont.AsInt64()) { + lastFiFont = INT_MIN; + lastStdFont = AStdFont.AsInt64(); + } + if(AsInt64() == lastFiFont) + return lastFontInfo; + lastFontInfo = GetFontInfo(*this); + lastFiFont = AsInt64(); + return lastFontInfo; +} + +FontInfo Font::Info() const +{ + FontInfo h; + h.font = *this; + return h; +} + +END_UPP_NAMESPACE diff --git a/uppsrc/Draw/FontFc.cpp b/uppsrc/Draw/FontFc.cpp index f4ab5375e..444fb1306 100644 --- a/uppsrc/Draw/FontFc.cpp +++ b/uppsrc/Draw/FontFc.cpp @@ -26,8 +26,6 @@ bool sInitFt(void) return FT_Init_FreeType(&sFTlib) == 0; } -int gtk_dpi = 96; - FcPattern *CreateFcPattern(Font font) { LTIMING("CreateXftFont"); @@ -39,12 +37,11 @@ FcPattern *CreateFcPattern(Font font) FcPatternAddString(p, FC_FAMILY, (FcChar8*)~face); FcPatternAddInteger(p, FC_SLANT, font.IsItalic() ? 110 : 0); FcPatternAddInteger(p, FC_PIXEL_SIZE, hg); - FcPatternAddInteger(p, FC_DPI, gtk_dpi); FcPatternAddInteger(p, FC_WEIGHT, font.IsBold() ? 200 : 100); FcPatternAddBool(p, FC_MINSPACE, 1); - FcResult result; FcConfigSubstitute(0, p, FcMatchPattern); FcDefaultSubstitute(p); + FcResult result; FcPattern *m = FcFontMatch(0, p, &result); FcPatternDestroy(p); return m; @@ -75,7 +72,7 @@ FT_Face CreateFTFace(const FcPattern *pattern, String *rpath) { FT_F26Dot6 ysize = (FT_F26Dot6) (dsize * 64.0); FT_F26Dot6 xsize = (FT_F26Dot6) (dsize * aspect * 64.0); - if(FT_New_Face (sFTlib, (const char *)filename, 0, &face)) + if(FT_New_Face(sFTlib, (const char *)filename, 0, &face)) return NULL; FT_Set_Char_Size(face, xsize, ysize, 0, 0); @@ -90,25 +87,35 @@ struct FtFaceEntry { String path; }; +static FtFaceEntry ft_cache[FONTCACHE]; + +void ClearFtFaceCache() +{ + for(int i = 0; i < FONTCACHE; i++) + ft_cache[i].font.Height(-30000); +} + +FT_Face (*FTFaceXft)(Font fnt, String *rpath); + FT_Face FTFace(Font fnt, String *rpath = NULL) { LTIMING("FTFace"); - static FtFaceEntry cache[FONTCACHE]; + if(FTFaceXft) + return (*FTFaceXft)(fnt, rpath); ONCELOCK { - for(int i = 0; i < FONTCACHE; i++) - cache[i].font.Height(-30000); + ClearFtFaceCache(); } FtFaceEntry be; - be = cache[0]; + be = ft_cache[0]; for(int i = 0; i < FONTCACHE; i++) { - FtFaceEntry e = cache[i]; + FtFaceEntry e = ft_cache[i]; if(i) - cache[i] = be; + ft_cache[i] = be; if(e.font == fnt) { if(rpath) *rpath = e.path; if(i) - cache[0] = e; + ft_cache[0] = e; return e.face; } be = e; @@ -122,16 +129,19 @@ FT_Face FTFace(Font fnt, String *rpath = NULL) FcPattern *p = CreateFcPattern(fnt); be.face = CreateFTFace(p, &be.path); FcPatternDestroy(p); - cache[0] = be; + ft_cache[0] = be; if(rpath) *rpath = be.path; return be.face; } +CommonFontInfo (*GetFontInfoSysXft)(Font font); + CommonFontInfo GetFontInfoSys(Font font) { + if(GetFontInfoSysXft) + return (*GetFontInfoSysXft)(font); CommonFontInfo fi; - String path; FT_Face face = FTFace(font, &path); if(face) { @@ -159,9 +169,13 @@ CommonFontInfo GetFontInfoSys(Font font) #define TRUNC(x) ((x) >> 6) #define ROUND(x) (((x)+32) & -64) +GlyphInfo (*GetGlyphInfoSysXft)(Font font, int chr); + GlyphInfo GetGlyphInfoSys(Font font, int chr) { LTIMING("GetGlyphInfoSys"); + if(GetGlyphInfoSysXft) + return (*GetGlyphInfoSysXft)(font, chr); GlyphInfo gi; FT_Face face = FTFace(font, NULL); gi.lspc = gi.rspc = 0; diff --git a/uppsrc/Painter/FontX11.cpp b/uppsrc/Painter/FontX11.cpp index 5ac89feda..24db30bf0 100644 --- a/uppsrc/Painter/FontX11.cpp +++ b/uppsrc/Painter/FontX11.cpp @@ -1,156 +1,155 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.4 -// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) -// -// Permission to copy, use, modify, sell and distribute this software -// is granted provided this copyright notice appears in all coM_PIes. -// This software is provided "as is" without express or implied -// warranty, and with no claim as to its suitability for any purpose. -// -//---------------------------------------------------------------------------- -// Contact: mcseem@antigrain.com -// mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- - -// Recycled for U++ by Miroslav Fidler 2008 - -#include "Painter.h" - -#ifdef PLATFORM_POSIX -#include -#include - -NAMESPACE_UPP - -FT_Face FTFace(Font fnt, String *rpath); - -static inline double ft_dbl(int p) -{ - return double(p) / 64.0; -} - -bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy) -{ - FT_Vector v_last; - FT_Vector v_control; - FT_Vector v_start; - FT_Vector* point; - FT_Vector* limit; - char* tags; - int n; // index of contour in outline - char tag; // current point's state - int first = 0; // index of first point in contour - for(n = 0; n < outline.n_contours; n++) { - int last = outline.contours[n]; - limit = outline.points + last; - v_start = outline.points[first]; - v_last = outline.points[last]; - v_control = v_start; - point = outline.points + first; - tags = outline.tags + first; - tag = FT_CURVE_TAG(tags[0]); - if(tag == FT_CURVE_TAG_CUBIC) return false; - if(tag == FT_CURVE_TAG_CONIC) { - if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { - // start at last point if it is on the curve - v_start = v_last; - limit--; - } - else { - // if both first and last points are conic, - // start at their middle and record its position - // for closure - v_start.x = (v_start.x + v_last.x) / 2; - v_start.y = (v_start.y + v_last.y) / 2; - v_last = v_start; - } - point--; - tags--; - } - path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); - while(point < limit) { - point++; - tags++; - - tag = FT_CURVE_TAG(tags[0]); - switch(tag) { - case FT_CURVE_TAG_ON: - path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy); - continue; - case FT_CURVE_TAG_CONIC: - v_control.x = point->x; - v_control.y = point->y; - Do_Conic: - if(point < limit) { - FT_Vector vec; - FT_Vector v_middle; - point++; - tags++; - tag = FT_CURVE_TAG(tags[0]); - vec.x = point->x; - vec.y = point->y; - if(tag == FT_CURVE_TAG_ON) { - path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, - ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); - continue; - } - if(tag != FT_CURVE_TAG_CONIC) return false; - v_middle.x = (v_control.x + vec.x) / 2; - v_middle.y = (v_control.y + vec.y) / 2; - path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, - ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy); - v_control = vec; - goto Do_Conic; - } - path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, - ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); - goto Close; - - default: - FT_Vector vec1, vec2; - if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) - return false; - vec1.x = point[0].x; - vec1.y = point[0].y; - vec2.x = point[1].x; - vec2.y = point[1].y; - point += 2; - tags += 2; - if(point <= limit) { - FT_Vector vec; - vec.x = point->x; - vec.y = point->y; - path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, - ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, - ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); - continue; - } - path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, - ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, - ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); - goto Close; - } - } - Close: - path.Close(); - first = last + 1; - } - return true; -} - -void PaintCharacterSys(Painter& sw, double x, double y, int ch, Font fnt) -{ - DrawLock __; - PAINTER_TIMING("CharacterOp"); - FT_Face face = FTFace(fnt, NULL); - int glyph_index = FT_Get_Char_Index(face, ch); - if(glyph_index && FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) - RenderOutline(face->glyph->outline, sw, x, y + fnt.GetAscent()); - sw.EvenOdd(true); -} - - -END_UPP_NAMESPACE - -#endif +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all coM_PIes. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +// Recycled for U++ by Miroslav Fidler 2008 + +#include "Painter.h" + +#ifdef PLATFORM_POSIX +#include +#include + +NAMESPACE_UPP + +FT_Face FTFace(Font fnt, String *rpath); + +static inline double ft_dbl(int p) +{ + return double(p) / 64.0; +} + +bool RenderOutline(const FT_Outline& outline, Painter& path, double xx, double yy) +{ + FT_Vector v_last; + FT_Vector v_control; + FT_Vector v_start; + FT_Vector* point; + FT_Vector* limit; + char* tags; + int n; // index of contour in outline + char tag; // current point's state + int first = 0; // index of first point in contour + for(n = 0; n < outline.n_contours; n++) { + int last = outline.contours[n]; + limit = outline.points + last; + v_start = outline.points[first]; + v_last = outline.points[last]; + v_control = v_start; + point = outline.points + first; + tags = outline.tags + first; + tag = FT_CURVE_TAG(tags[0]); + if(tag == FT_CURVE_TAG_CUBIC) return false; + if(tag == FT_CURVE_TAG_CONIC) { + if(FT_CURVE_TAG(outline.tags[last]) == FT_CURVE_TAG_ON) { + // start at last point if it is on the curve + v_start = v_last; + limit--; + } + else { + // if both first and last points are conic, + // start at their middle and record its position + // for closure + v_start.x = (v_start.x + v_last.x) / 2; + v_start.y = (v_start.y + v_last.y) / 2; + v_last = v_start; + } + point--; + tags--; + } + path.Move(ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + while(point < limit) { + point++; + tags++; + + tag = FT_CURVE_TAG(tags[0]); + switch(tag) { + case FT_CURVE_TAG_ON: + path.Line(ft_dbl(point->x) + xx, -ft_dbl(point->y) + yy); + continue; + case FT_CURVE_TAG_CONIC: + v_control.x = point->x; + v_control.y = point->y; + Do_Conic: + if(point < limit) { + FT_Vector vec; + FT_Vector v_middle; + point++; + tags++; + tag = FT_CURVE_TAG(tags[0]); + vec.x = point->x; + vec.y = point->y; + if(tag == FT_CURVE_TAG_ON) { + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); + continue; + } + if(tag != FT_CURVE_TAG_CONIC) return false; + v_middle.x = (v_control.x + vec.x) / 2; + v_middle.y = (v_control.y + vec.y) / 2; + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(v_middle.x) + xx, -ft_dbl(v_middle.y) + yy); + v_control = vec; + goto Do_Conic; + } + path.Quadratic(ft_dbl(v_control.x) + xx, -ft_dbl(v_control.y) + yy, + ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + goto Close; + + default: + FT_Vector vec1, vec2; + if(point + 1 > limit || FT_CURVE_TAG(tags[1]) != FT_CURVE_TAG_CUBIC) + return false; + vec1.x = point[0].x; + vec1.y = point[0].y; + vec2.x = point[1].x; + vec2.y = point[1].y; + point += 2; + tags += 2; + if(point <= limit) { + FT_Vector vec; + vec.x = point->x; + vec.y = point->y; + path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(vec.x) + xx, -ft_dbl(vec.y) + yy); + continue; + } + path.Cubic(ft_dbl(vec1.x) + xx, -ft_dbl(vec1.y) + yy, + ft_dbl(vec2.x) + xx, -ft_dbl(vec2.y) + yy, + ft_dbl(v_start.x) + xx, -ft_dbl(v_start.y) + yy); + goto Close; + } + } + Close: + path.Close(); + first = last + 1; + } + return true; +} + +void PaintCharacterSys(Painter& sw, double x, double y, int ch, Font fnt) +{ + DrawLock __; + PAINTER_TIMING("CharacterOp"); + FT_Face face = FTFace(fnt, NULL); + int glyph_index = FT_Get_Char_Index(face, ch); + if(glyph_index && FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT) == 0) + RenderOutline(face->glyph->outline, sw, x, y + fnt.GetAscent()); + sw.EvenOdd(true); +} + +END_UPP_NAMESPACE + +#endif diff --git a/uppsrc/PdfDraw/PdfDraw.cpp b/uppsrc/PdfDraw/PdfDraw.cpp index 0225bf189..0d19ff396 100644 --- a/uppsrc/PdfDraw/PdfDraw.cpp +++ b/uppsrc/PdfDraw/PdfDraw.cpp @@ -267,7 +267,7 @@ PdfDraw::OutlineInfo PdfDraw::GetOutlineInfo(Font fnt) } } #endif -#ifdef PLATFORM_X11 +#ifdef PLATFORM_POSIX FontInfo fi = fnt.Info(); String fn = fi.GetFileName(); String ext = ToLower(GetFileExt(fn)); @@ -299,7 +299,7 @@ void PdfDraw::DrawTextOp(int x, int y, int angle, const wchar *s, Font fnt, #ifdef PLATFORM_WIN32 int fh = ff.GetHeight() - ff.GetInternal();//TODO #endif - #ifdef PLATFORM_X11 + #ifdef PLATFORM_POSIX int fh = fnt.GetHeight(); #endif OutlineInfo of = GetOutlineInfo(fnt); diff --git a/uppsrc/PdfDraw/init b/uppsrc/PdfDraw/init index d3fcc17d0..4dd51c021 100644 --- a/uppsrc/PdfDraw/init +++ b/uppsrc/PdfDraw/init @@ -1,7 +1,7 @@ #ifndef _PdfDraw_icpp_init_stub #define _PdfDraw_icpp_init_stub #include "Draw/init" -#define BLITZ_INDEX__ F2EB858D15FF91342F7F9648AA934C9C8 +#define BLITZ_INDEX__ FA6D939FEC0881A8606B7621CDFC33471 #include "PdfReport.icpp" #undef BLITZ_INDEX__ #endif diff --git a/uppsrc/ide/Core/Host.cpp b/uppsrc/ide/Core/Host.cpp index 455c7f4f7..4e76d7271 100644 --- a/uppsrc/ide/Core/Host.cpp +++ b/uppsrc/ide/Core/Host.cpp @@ -1,565 +1,564 @@ -#include "Core.h" - -#define LLOG(x) - -#include - -String LocalHost::GetEnvironment() -{ - return environment; -} - -String LocalHost::GetHostPath(const String& path) -{ - return path; -} - -String LocalHost::GetLocalPath(const String& path) -{ - return path; -} - -String LocalHost::NormalizePath(const String& path) -{ - return ::NormalizePath(path); -} - -Vector LocalHost::GetFileInfo(const Vector& path) -{ - Vector fi; - for(int i = 0; i < path.GetCount(); i++) { - FindFile ff(path[i]); - FileInfo& f = fi.Add(); - if(ff) { - (Time&)f = ff.GetLastWriteTime(); -#ifdef PLATFORM_WIN32 - f.second = f.second & ~1; // FAT vs NTFS accuracy fix -#endif - f.length = ff.IsFile() ? (int)ff.GetLength() : -1; - } - else { - (Time&)f = Time::Low(); - f.length = Null; - } - } - return fi; -} - -void LocalHost::DeleteFile(const Vector& path) -{ - for(int i = 0; i < path.GetCount(); i++) - ::DeleteFile(path[i]); -} - -void LocalHost::DeleteFolderDeep(const String& folder) -{ - ::DeleteFolderDeep(folder); -} - -void LocalHost::ChDir(const String& path) -{ -#ifdef PLATFORM_WIN32 - SetCurrentDirectory(path); -#endif -#ifdef PLATFORM_POSIX - chdir(path); -#endif - if(cmdout) - *cmdout << "cd \"" << GetHostPath(path) << "\"\n"; -} - -void LocalHost::DoDir(const String& dir) -{ - if(dir.GetLength() > 3) { - DoDir(GetFileFolder(dir)); - *cmdout << "mkdir \"" << dir << "\"\n"; - } -} - -void LocalHost::RealizeDir(const String& path) -{ - RealizeDirectory(path); - if(cmdout) - DoDir(path); -} - -void LocalHost::SaveFile(const String& path, const String& data) -{ - ::SaveFile(path, data); -} - -String LocalHost::LoadFile(const String& path) -{ - return ::LoadFile(path); -} - -int LocalHost::Execute(const char *cmdline) -{ - if(cmdout) - *cmdout << cmdline << '\n'; - PutVerbose(cmdline); - int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), NULL, environment, false); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::ExecuteWithInput(const char *cmdline) -{ - if(cmdout) - *cmdout << cmdline << '\n'; - PutVerbose(cmdline); - int q = IdeConsoleExecuteWithInput(FindCommand(exedirs, cmdline), NULL, environment, false); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::Execute(const char *cmdline, Stream& out) -{ - PutVerbose(cmdline); - int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), &out, environment, true); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int LocalHost::AllocSlot() -{ - return IdeConsoleAllocSlot(); -} - -bool LocalHost::Run(const char *cmdline, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(FindCommand(exedirs, cmdline), NULL, environment, false, slot, key, blitz_count); -} - -bool LocalHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(FindCommand(exedirs, cmdline), &out, environment, true, slot, key, blitz_count); -} - -bool LocalHost::Wait() -{ - return IdeConsoleWait(); -} - -One LocalHost::StartProcess(const char *cmdline) -{ - try { - PutVerbose(cmdline); - return ::StartProcess(FindCommand(exedirs, cmdline), environment, REMOTE_TIMEOUT); - } - catch(...) { - return NULL; - } -} - -#ifdef PLATFORM_POSIX -//#BLITZ_APPROVE -#include -#include -#include - -static Vector& sPid() -{ - static Vector q; - return q; -} - -void sCleanZombies(int signal_number) -{ - Vector& pid = sPid(); - int i = 0; - while(i < pid.GetCount()) - if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) - pid.Remove(i); - else - i++; -} -#endif - -String LinuxHostConsole = "/usr/bin/xterm -e"; - -void LocalHost::Launch(const char *_cmdline, bool console) -{ - String cmdline = FindCommand(exedirs, _cmdline); - PutVerbose(cmdline); -#ifdef PLATFORM_WIN32 - if(console) - cmdline = GetExeFilePath() + " ! " + cmdline; - int n = cmdline.GetLength() + 1; - Buffer cmd(n); - memcpy(cmd, cmdline, n); - SECURITY_ATTRIBUTES sa; - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.lpSecurityDescriptor = NULL; - sa.bInheritHandle = TRUE; - PROCESS_INFORMATION pi; - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - Buffer env(environment.GetCount() + 1); - memcpy(env, environment, environment.GetCount() + 1); - if(CreateProcess(NULL, cmd, &sa, &sa, TRUE, - NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, - ~env, NULL, &si, &pi)) { - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - else - PutConsole("Unable to launch " + String(_cmdline)); -#endif -#ifdef PLATFORM_POSIX - String script = ConfigFile("console-script-" + AsString(getpid()) + ".tmp"); - if(console) { - FileStream out(script, FileStream::CREATE, 0777); - out << "#!/bin/sh\n" - << cmdline << '\n' - << "echo \"<--- Finished, press any key to close the window --->\"\nread\n"; - cmdline = LinuxHostConsole + " sh " + script; - } - Buffer cmd_buf(strlen(cmdline) + 1); - char *cmd_out = cmd_buf; - Vector args; - const char *p = cmdline; - const char *b = p; - while(*p && (byte)*p > ' ') - if(*p++ == '\"') - while(*p && *p++ != '\"') - ; - args.Add(cmd_out); - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - *cmd_out++ = '\0'; - - while(*p) - if((byte)*p <= ' ') - p++; - else { - args.Add(cmd_out); - b = p; - while(*p && (byte)*p > ' ') - if(*p++ == '\"') - { - memcpy(cmd_out, b, p - b - 1); - cmd_out += p - b - 1; - b = p; - while(*p && *p != '\"') - p++; - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - if(*p == '\"') - p++; - b = p; - } - memcpy(cmd_out, b, p - b); - cmd_out += p - b; - *cmd_out++ = '\0'; - } - - args.Add(NULL); - - ONCELOCK { - struct sigaction sigchld_action; - memset(&sigchld_action, 0, sizeof(sigchld_action)); - sigchld_action.sa_handler = sCleanZombies; - sigaction(SIGCHLD, &sigchld_action, NULL); - } - - pid_t pid = fork(); - if(pid == 0) - { - const char *from = environment; - Vector env; - while(*from) - { - env.Add(from); - from += strlen(from) + 1; - } - env.Add(NULL); - const char **envp = env.Begin(); - execve(args[0], args, (char *const *)envp); - abort(); - } - LLOG("Launch pid: " << pid); - sPid().Add(pid); -#endif -} - -void LocalHost::AddFlags(Index& cfg) -{ -#if defined(PLATFORM_WIN32) - cfg.Add("WIN32"); -#endif - -#ifdef PLATFORM_LINUX - cfg.Add("LINUX"); -#endif - -#ifdef PLATFORM_POSIX - cfg.Add("POSIX"); -#endif - -#ifdef PLATFORM_BSD - cfg.Add("BSD"); -#endif - -#ifdef PLATFORM_FREEBSD - cfg.Add("FREEBSD"); -#endif - -#ifdef PLATFORM_OPENBSD - cfg.Add("OPENBSD"); -#endif - -#ifdef PLATFORM_NETBSD - cfg.Add("NETBSD"); -#endif - -#ifdef PLATFORM_SOLARIS - cfg.Add("SOLARIS"); -#endif - -#ifdef PLATFORM_OSX11 - cfg.Add("OSX11"); -#endif -} - -static bool IsSamePath(const char *a, const char *b, int count) { - for(; --count >= 0; a++, b++) - if(a != b && ToLower(*a) != ToLower(*b) && !((*a == '\\' || *a == '/') && (*b == '\\' || *b == '/'))) - return false; - return true; -} - -String RemoteHost::GetEnvironment() -{ - return environment; -} - -String RemoteHost::GetHostPath(const String& path) -{ - bool slash = (os_type != "WINDOWS"); - for(int i = 0; i < path_map_local.GetCount(); i++) { - String lc = path_map_local[i]; - if(path.GetLength() >= lc.GetLength() && IsSamePath(path, lc, lc.GetLength())) - { - String r = CatAnyPath(path_map_remote[i], path.Mid(lc.GetLength())); - return slash ? UnixPath(r) : WinPath(r); - } - } - return slash ? UnixPath(path) : WinPath(path); -} - -String RemoteHost::GetLocalPath(const String& path) -{ - for(int i = 0; i < path_map_remote.GetCount(); i++) { - String rc = path_map_remote[i]; - if(path.GetLength() >= rc.GetLength() && IsSamePath(path, rc, rc.GetLength())) - return path_map_local[i] + path.Mid(rc.GetLength()); - } - if(!memcmp(path, "/cygdrive/", 10)) - { - const char *s = path.Begin() + 10; - String out; - if(*s) - out << *s++ << ':'; - out << s; - return out; - } - return NativePath(path); -} - -String RemoteHost::NormalizePath(const String& path) -{ - return path; -} - -String RemoteHost::RemoteExec(String cmd) -{ - Socket socket; - String sockerr; -/* - String hostname = host; - int port = 2346; - int ppos = hostname.Find(':'); - if(ppos >= 0) - { - port = atoi(host.GetIter(ppos + 1)); - hostname.Trim(ppos); - } -*/ - if(!ClientSocket(socket, host, port, true, NULL, 2000)) { - PutConsole(NFormat("Error connecting to '%s', port %d: %s", host, port, Socket::GetErrorText())); - return String::GetVoid(); - } - socket.Write(cmd); - socket.Write("\0", 1); - return socket.ReadUntil('\0', Null, 10000000); -} - -Vector RemoteHost::GetFileInfo(const Vector& path) -{ - VectorMap out; - out.Reserve(path.GetCount()); - String request; - request << "@" << (int)(GetSysTime() - TimeBase()) << ":"; - for(int i = 0; i < path.GetCount(); i++) - { - String hp = GetHostPath(path[i]); - request << hp << "\n"; - FileInfo& fi = out.Add(hp); - (Time&)fi = Time::Low(); - fi.length = Null; - } - String result = RemoteExec(request); - const char *p = result; - while(*p) - { - const char *b = p; - while(*p && *p != '\n' && *p != '\t') - p++; - String fn(b, p); - Time time = Time::Low(); - int size = Null; - if(*p == '\t') - { - int t = ScanInt(p + 1, &p); - if(!IsNull(t)) - time = TimeBase() + t; - if(*p == '\t') - size = ScanInt(p + 1, &p); - } - int ifn = out.Find(fn); - if(ifn >= 0) - { - (Time&)out[ifn] = time; - out[ifn].length = size; - } - while(*p && *p++ != '\n') - ; - } - return out.PickValues(); -} - -void RemoteHost::DeleteFile(const Vector& path) -{ - String request = "-"; - for(int i = 0; i < path.GetCount(); i++) - request << GetHostPath(path[i]) << "\n"; - String out = RemoteExec(request); - if(!IsNull(out) && out != "OK") - PutVerbose(out); -} - -void RemoteHost::DeleteFolderDeep(const String& folder) -{ - String out = RemoteExec("~" + GetHostPath(folder)); - if(out != "OK") - PutConsole(out); -} - -void RemoteHost::ChDir(const String& path) -{ - chdir_path = GetHostPath(path); -} - -void RemoteHost::RealizeDir(const String& path) -{ - RemoteExec("*" + GetHostPath(path)); -} - -void RemoteHost::SaveFile(const String& path, const String& data) -{ - String request; - request << ">" << GetHostPath(path) - << "\t" << int(GetSysTime() - TimeBase()) - << "\t" << data.GetLength() - << "\t" << ASCII85Encode(BZ2Compress(data)) - << "\n"; - String out = RemoteExec(request); - if(out != "OK") - PutConsole(out); -} - -String RemoteHost::LoadFile(const String& path) -{ - String hpath = GetHostPath(path); - String request = "^" + hpath; - String out = RemoteExec(request); - const char *p = out; - while(*p && *p != '\n' && *p != '\t') - p++; - if(*p++ != '\t') - return String::GetVoid(); - int len = ScanInt(p, &p); - if(IsNull(len) || len <= 0 || *p++ != '\t') - return String::GetVoid(); - String data = BZ2Decompress(ASCII85Decode(p)); - if(data.GetLength() != len) - { - PutConsole(NFormat("%s: decompressed length (%d) doesn't match length in header (%d)", - hpath, data.GetLength(), len)); - return String::GetVoid(); - } - return data; -} - -int RemoteHost::Execute(const char *cmdline) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::ExecuteWithInput(const char *cmdline) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::Execute(const char *cmdline, Stream& out) -{ - int q = IdeConsoleExecute(StartProcess(cmdline), cmdline, &out, true); - PutVerbose(Format("Exitcode: %d", q)); - return q; -} - -int RemoteHost::AllocSlot() -{ - return IdeConsoleAllocSlot(); -} - -bool RemoteHost::Run(const char *cmdline, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(StartProcess(cmdline), cmdline, NULL, false, slot, key, blitz_count); -} - -bool RemoteHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) -{ - return IdeConsoleRun(StartProcess(cmdline), cmdline, &out, false, slot, key, blitz_count); -} - -bool RemoteHost::Wait() -{ - return IdeConsoleWait(); -} - -One RemoteHost::StartProcess(const char *cmdline) -{ - try { - PutVerbose(cmdline); - return StartRemoteProcess(host, port, cmdline, environment, REMOTE_TIMEOUT); - } - catch(...) { - return NULL; - } -} - -void RemoteHost::Launch(const char *_cmdline, bool) -{ -} - -void RemoteHost::AddFlags(Index& cfg) -{ - cfg.Add(os_type); -} +#include "Core.h" + +#define LLOG(x) + +#include + +String LocalHost::GetEnvironment() +{ + return environment; +} + +String LocalHost::GetHostPath(const String& path) +{ + return path; +} + +String LocalHost::GetLocalPath(const String& path) +{ + return path; +} + +String LocalHost::NormalizePath(const String& path) +{ + return ::NormalizePath(path); +} + +Vector LocalHost::GetFileInfo(const Vector& path) +{ + Vector fi; + for(int i = 0; i < path.GetCount(); i++) { + FindFile ff(path[i]); + FileInfo& f = fi.Add(); + if(ff) { + (Time&)f = ff.GetLastWriteTime(); +#ifdef PLATFORM_WIN32 + f.second = f.second & ~1; // FAT vs NTFS accuracy fix +#endif + f.length = ff.IsFile() ? (int)ff.GetLength() : -1; + } + else { + (Time&)f = Time::Low(); + f.length = Null; + } + } + return fi; +} + +void LocalHost::DeleteFile(const Vector& path) +{ + for(int i = 0; i < path.GetCount(); i++) + ::DeleteFile(path[i]); +} + +void LocalHost::DeleteFolderDeep(const String& folder) +{ + ::DeleteFolderDeep(folder); +} + +void LocalHost::ChDir(const String& path) +{ +#ifdef PLATFORM_WIN32 + SetCurrentDirectory(path); +#endif +#ifdef PLATFORM_POSIX + chdir(path); +#endif + if(cmdout) + *cmdout << "cd \"" << GetHostPath(path) << "\"\n"; +} + +void LocalHost::DoDir(const String& dir) +{ + if(dir.GetLength() > 3) { + DoDir(GetFileFolder(dir)); + *cmdout << "mkdir \"" << dir << "\"\n"; + } +} + +void LocalHost::RealizeDir(const String& path) +{ + RealizeDirectory(path); + if(cmdout) + DoDir(path); +} + +void LocalHost::SaveFile(const String& path, const String& data) +{ + ::SaveFile(path, data); +} + +String LocalHost::LoadFile(const String& path) +{ + return ::LoadFile(path); +} + +int LocalHost::Execute(const char *cmdline) +{ + if(cmdout) + *cmdout << cmdline << '\n'; + PutVerbose(cmdline); + int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), NULL, environment, false); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::ExecuteWithInput(const char *cmdline) +{ + if(cmdout) + *cmdout << cmdline << '\n'; + PutVerbose(cmdline); + int q = IdeConsoleExecuteWithInput(FindCommand(exedirs, cmdline), NULL, environment, false); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::Execute(const char *cmdline, Stream& out) +{ + PutVerbose(cmdline); + int q = IdeConsoleExecute(FindCommand(exedirs, cmdline), &out, environment, true); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int LocalHost::AllocSlot() +{ + return IdeConsoleAllocSlot(); +} + +bool LocalHost::Run(const char *cmdline, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(FindCommand(exedirs, cmdline), NULL, environment, false, slot, key, blitz_count); +} + +bool LocalHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(FindCommand(exedirs, cmdline), &out, environment, true, slot, key, blitz_count); +} + +bool LocalHost::Wait() +{ + return IdeConsoleWait(); +} + +One LocalHost::StartProcess(const char *cmdline) +{ + try { + PutVerbose(cmdline); + return ::StartProcess(FindCommand(exedirs, cmdline), environment, REMOTE_TIMEOUT); + } + catch(...) { + return NULL; + } +} + +#ifdef PLATFORM_POSIX +//#BLITZ_APPROVE +#include +#include +#include + +static Vector& sPid() +{ + static Vector q; + return q; +} + +void sCleanZombies(int signal_number) +{ + Vector& pid = sPid(); + int i = 0; + while(i < pid.GetCount()) + if(pid[i] && waitpid(pid[i], 0, WNOHANG | WUNTRACED) > 0) + pid.Remove(i); + else + i++; +} +#endif + +String LinuxHostConsole = "/usr/bin/xterm -e"; + +void LocalHost::Launch(const char *_cmdline, bool console) +{ + String cmdline = FindCommand(exedirs, _cmdline); + PutVerbose(cmdline); +#ifdef PLATFORM_WIN32 + if(console) + cmdline = GetExeFilePath() + " ! " + cmdline; + int n = cmdline.GetLength() + 1; + Buffer cmd(n); + memcpy(cmd, cmdline, n); + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + PROCESS_INFORMATION pi; + STARTUPINFO si; + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + Buffer env(environment.GetCount() + 1); + memcpy(env, environment, environment.GetCount() + 1); + if(CreateProcess(NULL, cmd, &sa, &sa, TRUE, + NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE, + ~env, NULL, &si, &pi)) { + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + else + PutConsole("Unable to launch " + String(_cmdline)); +#endif +#ifdef PLATFORM_POSIX + String script = ConfigFile("console-script-" + AsString(getpid()) + ".tmp"); + if(console) { + FileStream out(script, FileStream::CREATE, 0777); + out << "#!/bin/sh\n" + << cmdline << '\n' + << "echo \"<--- Finished, press any key to close the window --->\"\nread\n"; + cmdline = LinuxHostConsole + " sh " + script; + } + Buffer cmd_buf(strlen(cmdline) + 1); + char *cmd_out = cmd_buf; + Vector args; + const char *p = cmdline; + const char *b = p; + while(*p && (byte)*p > ' ') + if(*p++ == '\"') + while(*p && *p++ != '\"') + ; + args.Add(cmd_out); + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + *cmd_out++ = '\0'; + + while(*p) + if((byte)*p <= ' ') + p++; + else { + args.Add(cmd_out); + b = p; + while(*p && (byte)*p > ' ') + if(*p++ == '\"') + { + memcpy(cmd_out, b, p - b - 1); + cmd_out += p - b - 1; + b = p; + while(*p && *p != '\"') + p++; + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + if(*p == '\"') + p++; + b = p; + } + memcpy(cmd_out, b, p - b); + cmd_out += p - b; + *cmd_out++ = '\0'; + } + + args.Add(NULL); + + ONCELOCK { + struct sigaction sigchld_action; + memset(&sigchld_action, 0, sizeof(sigchld_action)); + sigchld_action.sa_handler = sCleanZombies; + sigaction(SIGCHLD, &sigchld_action, NULL); + } + + pid_t pid = fork(); + if(pid == 0) + { + const char *from = environment; + Vector env; + while(*from) { + env.Add(from); + from += strlen(from) + 1; + } + env.Add(NULL); + const char **envp = env.Begin(); + execve(args[0], args, (char *const *)envp); + abort(); + } + LLOG("Launch pid: " << pid); + sPid().Add(pid); +#endif +} + +void LocalHost::AddFlags(Index& cfg) +{ +#if defined(PLATFORM_WIN32) + cfg.Add("WIN32"); +#endif + +#ifdef PLATFORM_LINUX + cfg.Add("LINUX"); +#endif + +#ifdef PLATFORM_POSIX + cfg.Add("POSIX"); +#endif + +#ifdef PLATFORM_BSD + cfg.Add("BSD"); +#endif + +#ifdef PLATFORM_FREEBSD + cfg.Add("FREEBSD"); +#endif + +#ifdef PLATFORM_OPENBSD + cfg.Add("OPENBSD"); +#endif + +#ifdef PLATFORM_NETBSD + cfg.Add("NETBSD"); +#endif + +#ifdef PLATFORM_SOLARIS + cfg.Add("SOLARIS"); +#endif + +#ifdef PLATFORM_OSX11 + cfg.Add("OSX11"); +#endif +} + +static bool IsSamePath(const char *a, const char *b, int count) { + for(; --count >= 0; a++, b++) + if(a != b && ToLower(*a) != ToLower(*b) && !((*a == '\\' || *a == '/') && (*b == '\\' || *b == '/'))) + return false; + return true; +} + +String RemoteHost::GetEnvironment() +{ + return environment; +} + +String RemoteHost::GetHostPath(const String& path) +{ + bool slash = (os_type != "WINDOWS"); + for(int i = 0; i < path_map_local.GetCount(); i++) { + String lc = path_map_local[i]; + if(path.GetLength() >= lc.GetLength() && IsSamePath(path, lc, lc.GetLength())) + { + String r = CatAnyPath(path_map_remote[i], path.Mid(lc.GetLength())); + return slash ? UnixPath(r) : WinPath(r); + } + } + return slash ? UnixPath(path) : WinPath(path); +} + +String RemoteHost::GetLocalPath(const String& path) +{ + for(int i = 0; i < path_map_remote.GetCount(); i++) { + String rc = path_map_remote[i]; + if(path.GetLength() >= rc.GetLength() && IsSamePath(path, rc, rc.GetLength())) + return path_map_local[i] + path.Mid(rc.GetLength()); + } + if(!memcmp(path, "/cygdrive/", 10)) + { + const char *s = path.Begin() + 10; + String out; + if(*s) + out << *s++ << ':'; + out << s; + return out; + } + return NativePath(path); +} + +String RemoteHost::NormalizePath(const String& path) +{ + return path; +} + +String RemoteHost::RemoteExec(String cmd) +{ + Socket socket; + String sockerr; +/* + String hostname = host; + int port = 2346; + int ppos = hostname.Find(':'); + if(ppos >= 0) + { + port = atoi(host.GetIter(ppos + 1)); + hostname.Trim(ppos); + } +*/ + if(!ClientSocket(socket, host, port, true, NULL, 2000)) { + PutConsole(NFormat("Error connecting to '%s', port %d: %s", host, port, Socket::GetErrorText())); + return String::GetVoid(); + } + socket.Write(cmd); + socket.Write("\0", 1); + return socket.ReadUntil('\0', Null, 10000000); +} + +Vector RemoteHost::GetFileInfo(const Vector& path) +{ + VectorMap out; + out.Reserve(path.GetCount()); + String request; + request << "@" << (int)(GetSysTime() - TimeBase()) << ":"; + for(int i = 0; i < path.GetCount(); i++) + { + String hp = GetHostPath(path[i]); + request << hp << "\n"; + FileInfo& fi = out.Add(hp); + (Time&)fi = Time::Low(); + fi.length = Null; + } + String result = RemoteExec(request); + const char *p = result; + while(*p) + { + const char *b = p; + while(*p && *p != '\n' && *p != '\t') + p++; + String fn(b, p); + Time time = Time::Low(); + int size = Null; + if(*p == '\t') + { + int t = ScanInt(p + 1, &p); + if(!IsNull(t)) + time = TimeBase() + t; + if(*p == '\t') + size = ScanInt(p + 1, &p); + } + int ifn = out.Find(fn); + if(ifn >= 0) + { + (Time&)out[ifn] = time; + out[ifn].length = size; + } + while(*p && *p++ != '\n') + ; + } + return out.PickValues(); +} + +void RemoteHost::DeleteFile(const Vector& path) +{ + String request = "-"; + for(int i = 0; i < path.GetCount(); i++) + request << GetHostPath(path[i]) << "\n"; + String out = RemoteExec(request); + if(!IsNull(out) && out != "OK") + PutVerbose(out); +} + +void RemoteHost::DeleteFolderDeep(const String& folder) +{ + String out = RemoteExec("~" + GetHostPath(folder)); + if(out != "OK") + PutConsole(out); +} + +void RemoteHost::ChDir(const String& path) +{ + chdir_path = GetHostPath(path); +} + +void RemoteHost::RealizeDir(const String& path) +{ + RemoteExec("*" + GetHostPath(path)); +} + +void RemoteHost::SaveFile(const String& path, const String& data) +{ + String request; + request << ">" << GetHostPath(path) + << "\t" << int(GetSysTime() - TimeBase()) + << "\t" << data.GetLength() + << "\t" << ASCII85Encode(BZ2Compress(data)) + << "\n"; + String out = RemoteExec(request); + if(out != "OK") + PutConsole(out); +} + +String RemoteHost::LoadFile(const String& path) +{ + String hpath = GetHostPath(path); + String request = "^" + hpath; + String out = RemoteExec(request); + const char *p = out; + while(*p && *p != '\n' && *p != '\t') + p++; + if(*p++ != '\t') + return String::GetVoid(); + int len = ScanInt(p, &p); + if(IsNull(len) || len <= 0 || *p++ != '\t') + return String::GetVoid(); + String data = BZ2Decompress(ASCII85Decode(p)); + if(data.GetLength() != len) + { + PutConsole(NFormat("%s: decompressed length (%d) doesn't match length in header (%d)", + hpath, data.GetLength(), len)); + return String::GetVoid(); + } + return data; +} + +int RemoteHost::Execute(const char *cmdline) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::ExecuteWithInput(const char *cmdline) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::Execute(const char *cmdline, Stream& out) +{ + int q = IdeConsoleExecute(StartProcess(cmdline), cmdline, &out, true); + PutVerbose(Format("Exitcode: %d", q)); + return q; +} + +int RemoteHost::AllocSlot() +{ + return IdeConsoleAllocSlot(); +} + +bool RemoteHost::Run(const char *cmdline, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(StartProcess(cmdline), cmdline, NULL, false, slot, key, blitz_count); +} + +bool RemoteHost::Run(const char *cmdline, Stream& out, int slot, String key, int blitz_count) +{ + return IdeConsoleRun(StartProcess(cmdline), cmdline, &out, false, slot, key, blitz_count); +} + +bool RemoteHost::Wait() +{ + return IdeConsoleWait(); +} + +One RemoteHost::StartProcess(const char *cmdline) +{ + try { + PutVerbose(cmdline); + return StartRemoteProcess(host, port, cmdline, environment, REMOTE_TIMEOUT); + } + catch(...) { + return NULL; + } +} + +void RemoteHost::Launch(const char *_cmdline, bool) +{ +} + +void RemoteHost::AddFlags(Index& cfg) +{ + cfg.Add(os_type); +} diff --git a/uppsrc/usvn/SvnSync.cpp b/uppsrc/usvn/SvnSync.cpp index bfd869fdb..2938aa410 100644 --- a/uppsrc/usvn/SvnSync.cpp +++ b/uppsrc/usvn/SvnSync.cpp @@ -1,364 +1,364 @@ -#include "usvn.h" - -bool CheckSvn() -{ - String h; - if(Sys("svn", h) >= 0) - return true; -#ifdef PLATFORM_WIN32 - Exclamation("Unable to execute svn.exe!&" - "You can download svn client here: [^http://www.sliksvn.com/en/download^ http://www.sliksvn.com/en/download]"); -#else - Exclamation("Unable to execute 'svn' binary!&Please install svn client."); -#endif - return false; -} - -SvnSync::SvnSync() -{ - CtrlLayoutOKCancel(*this, "SvnSynchronize SVN repositories"); - list.AddIndex(); - list.AddIndex(); - list.AddColumn("Action"); - list.AddColumn("Path"); - list.AddColumn("Changes"); - list.ColumnWidths("170 500 100"); - list.NoCursor().EvenRowColor(); - list.SetLineCy(max(Draw::GetStdFontCy(), 20)); - list.WhenLeftClick = THISBACK(Diff); - Sizeable().Zoomable(); - setup <<= THISBACK(Setup); - BackPaint(); -} - -void SvnSync::Setup() -{ - works.Execute(); - SyncList(); -} - -int CharFilterSvnMsg(int c) -{ - return c >= 32 && c < 128 && c != '\"' ? c : 0; -} - -void SvnSync::SyncList() -{ - list.Clear(); - for(int i = 0; i < works.GetCount(); i++) { - SvnWork w = works[i]; - String path = GetFullPath(w.working); - list.Add(REPOSITORY, path, - AttrText("Working directory").SetFont(StdFont().Bold()).Ink(White).Paper(Blue), - AttrText(path).SetFont(Arial(20).Bold()).Paper(Blue).Ink(White), - AttrText("").SetFont(Arial(20).Bold()).Paper(Blue).Ink(White)); - list.SetLineCy(list.GetCount() - 1, 26); - Vector ln = Split(Sys("svn status " + path), CharFilterCrLf); - bool actions = false; - for(int pass = 0; pass < 2; pass++) - for(int i = 0; i < ln.GetCount(); i++) { - String h = ln[i]; - if(h.GetCount() > 7) { - String file = h.Mid(7); - if(IsFullPath(file)) { - actions = true; - h.Trim(7); - bool simple = h.Mid(1, 6) == " "; - int action = simple ? String("MC?!~").Find(h[0]) : -1; - if(h == " S ") - action = REPLACE; - String an; - Color color; - if(action < 0) { - color = Black; - if(simple && h[0] == 'A') - an = "svn add"; - else - if(simple && h[0] == 'D') - an = "svn delete"; - else { - an = h.Mid(0, 7); - color = Gray; - } - } - else { - int q = file.ReverseFind('.'); - if(action == ADD && q >= 0 && (file.Mid(q + 1) == "mine" || - file[q + 1] == 'r' && IsDigit(file[q + 2])) - && FileExists(file.Mid(0, q))) { - action = DELETEC; - an = "Delete"; - color = Black; - } - else { - static const char *as[] = { - "Modify", "Resolved", "Add", "Remove", "Replace" - }; - static Color c[] = { LtBlue, Magenta, Green, LtRed, LtMagenta }; - an = as[action]; - color = c[action]; - } - } - if(pass == action < 0) { - int ii = list.GetCount(); - list.Add(action, file, - action < 0 ? Value(AttrText(an).Ink(color)) : Value(true), - AttrText(" " + file.Mid(path.GetCount() + 1)).Ink(color)); - if(action >= 0) { - list.SetCtrl(ii, 0, revert.Add().SetLabel("Revert\n" + an).NoWantFocus()); - Ctrl& b = diff.Add().SetLabel("Changes..").SizePos().NoWantFocus(); - b <<= THISBACK1(DoDiff, ii); - list.SetCtrl(ii, 2, b); - } - } - } - } - } - if(actions) { - list.Add(MESSAGE, Null, AttrText("Commit message:").SetFont(StdFont().Bold())); - list.SetLineCy(list.GetCount() - 1, (3 * EditField::GetStdHeight()) + 4); - list.SetCtrl(list.GetCount() - 1, 1, message.Add().SetFilter(CharFilterSvnMsg).VSizePos(2, 2).HSizePos()); - int q = msgmap.Find(w.working); - if(q >= 0) { - message.Top() <<= msgmap[q]; - msgmap.Unlink(q); - } - } - else - list.Add(-1, Null, "", AttrText("Nothing to do").SetFont(StdFont().Italic())); - } -} - -void SvnSync::DoDiff(int ii) -{ - String f = list.Get(ii, 1); - if(!IsNull(f)) - RunSvnDiff(f); -} - -void SvnSync::Diff() -{ - int cr = list.GetClickRow(); - if(cr >= 0) - DoDiff(cr); -} - -#ifdef PLATFORM_WIN32 -void sDeleteFolderDeep(const char *dir) -{ - { - FindFile ff(AppendFileName(dir, "*.*")); - while(ff) { - String name = ff.GetName(); - String p = AppendFileName(dir, name); - if(ff.IsFile()) { - SetFileAttributes(p, GetFileAttributes(p) & ~FILE_ATTRIBUTE_READONLY); - FileDelete(p); - } - else - if(ff.IsFolder()) - sDeleteFolderDeep(p); - ff.Next(); - } - } - DirectoryDelete(dir); -} -#else -void sDeleteFolderDeep(const char *path) -{ - DeleteFolderDeep(path); -} -#endif - -void SvnDel(const char *path) -{ - FindFile ff(AppendFileName(path, "*.*")); - while(ff) { - if(ff.IsFolder()) { - String dir = AppendFileName(path, ff.GetName()); - if(ff.GetName() == ".svn") - sDeleteFolderDeep(dir); - else - SvnDel(dir); - } - ff.Next(); - } -} - -void SvnSync::Dir(const char *dir) -{ - setup.Hide(); - works.Add(dir, Null, Null); -} - -void SvnSync::Perform() -{ - if(!CheckSvn()) - return; - const Vector& cl = CommandLine(); - if(cl.GetCount()) - for(int i = 0; i < cl.GetCount(); i++) { - if(cl[i] == "-") { - works.Load(LoadFile(ConfigFile("svnworks"))); - DoSync(); - SaveFile(ConfigFile("svnworks"), works.Save()); - return; - } - String d = GetFullPath(cl[i]); - if(!DirectoryExists(cl[i])) { - Cerr() << cl[i] << " not a directory\n"; - SetExitCode(1); - return; - } - works.Add(d, "", ""); - } - else - works.Add(GetCurrentDirectory(), "", ""); - setup.Hide(); - DoSync(); -} - -void MoveSvn(const String& path, const String& tp) -{ - FindFile ff(AppendFileName(path, "*.*")); - while(ff) { - String nm = ff.GetName(); - String s = AppendFileName(path, nm); - String t = AppendFileName(tp, nm); - if(ff.IsFolder()) - if(nm == ".svn") - FileMove(s, t); - else - MoveSvn(s, t); - ff.Next(); - } -} - -void SvnSync::DoSync() -{ - SyncList(); - msgmap.Sweep(); -again: - if(Execute() != IDOK || list.GetCount() == 0) { - int repoi = 0; - for(int i = 0; i < list.GetCount(); i++) - if(list.Get(i, 0) == MESSAGE) - msgmap.GetAdd(works[repoi++].working) = list.Get(i, 3); - return; - } - bool changes = false; - for(int i = 0; i < list.GetCount(); i++) { - int action = list.Get(i, 0); - Value v = list.Get(i, 2); - if(action == MESSAGE) { - if(changes && IsNull(list.Get(i, 3)) - && !PromptYesNo("Commit message is empty.&Do you want to continue?")) - goto again; - changes = false; - } - else if(action != REPOSITORY && IsNumber(v) && (int)v) - changes = true; - } - SysConsole sys; - int repoi = 0; - int l = 0; - bool commit = false; - while(l < list.GetCount()) { - SvnWork w = works[repoi++]; - l++; - String message; - while(l < list.GetCount()) { - int action = list.Get(l, 0); - String path = list.Get(l, 1); - if(action == MESSAGE && commit) { - String msg = list.Get(l, 3); - if(sys.CheckSystem(SvnCmd("commit", w).Cat() << w.working << " -m \"" << msg << "\"")) - msgmap.GetAdd(w.working) = msg; - l++; - break; - } - if(action == REPOSITORY) - break; - Value v = list.Get(l, 2); - if(IsNumber(v) && (int)v == 0) { - if(action == REPLACE || action == ADD) - DeleteFolderDeep(path); - if(action != ADD) - sys.CheckSystem("svn revert " + path); - } - else { - commit = true; - switch(action) { - case ADD: - SvnDel(path); - sys.CheckSystem("svn add --force " + path); - break; - case REMOVE: - sys.CheckSystem("svn delete " + path); - break; - case CONFLICT: - sys.CheckSystem("svn resolved " + path); - break; - case REPLACE: { - SvnDel(path); - String tp = AppendFileName(GetFileFolder(path), Format(Uuid::Create())); - FileMove(path, tp); - sys.CheckSystem(SvnCmd("update", w).Cat() << ' ' << path); - MoveSvn(path, tp); - sDeleteFolderDeep(path); - FileMove(tp, path); - Vector ln = Split(Sys("svn status " + path), CharFilterCrLf); - for(int l = 0; l < ln.GetCount(); l++) { - String h = ln[l]; - if(h.GetCount() > 7) { - String file = h.Mid(7); - if(IsFullPath(file)) { - h.Trim(7); - if(h == "? ") - sys.CheckSystem("svn add --force " + file); - if(h == "! ") - sys.CheckSystem("svn delete " + file); - } - } - } - } - break; - case DELETEC: - FileDelete(path); - break; - } - } - l++; - } - sys.CheckSystem(SvnCmd("update", w).Cat() << w.working); - } - sys.Perform(); -} - -void SvnSync::SetMsgs(const String& s) -{ - LoadFromString(msgmap, s); -} - -String SvnSync::GetMsgs() -{ - return StoreAsString(msgmap); -} - -bool IsSvnDir(const String& p) -{ - return DirectoryExists(AppendFileName(p, ".svn")) || DirectoryExists(AppendFileName(p, "_svn")); -} - -#ifdef flagMAIN -GUI_APP_MAIN -{ - if(!CheckSvn()) - return; - SvnSync ss; - String mp = ConfigFile("usvn.msg"); - ss.SetMsgs(LoadFile(mp)); - ss.Perform(); - SaveFile(mp, ss.GetMsgs()); -} -#endif +#include "usvn.h" + +bool CheckSvn() +{ + String h; + if(Sys("svn", h) >= 0) + return true; +#ifdef PLATFORM_WIN32 + Exclamation("Unable to execute svn.exe!&" + "You can download svn client here: [^http://www.sliksvn.com/en/download^ http://www.sliksvn.com/en/download]"); +#else + Exclamation("Unable to execute 'svn' binary!&Please install svn client."); +#endif + return false; +} + +SvnSync::SvnSync() +{ + CtrlLayoutOKCancel(*this, "SvnSynchronize SVN repositories"); + list.AddIndex(); + list.AddIndex(); + list.AddColumn("Action"); + list.AddColumn("Path"); + list.AddColumn("Changes"); + list.ColumnWidths("170 500 100"); + list.NoCursor().EvenRowColor(); + list.SetLineCy(max(Draw::GetStdFontCy(), 20)); + list.WhenLeftClick = THISBACK(Diff); + Sizeable().Zoomable(); + setup <<= THISBACK(Setup); + BackPaint(); +} + +void SvnSync::Setup() +{ + works.Execute(); + SyncList(); +} + +int CharFilterSvnMsg(int c) +{ + return c >= 32 && c < 128 && c != '\"' ? c : 0; +} + +void SvnSync::SyncList() +{ + list.Clear(); + for(int i = 0; i < works.GetCount(); i++) { + SvnWork w = works[i]; + String path = GetFullPath(w.working); + list.Add(REPOSITORY, path, + AttrText("Working directory").SetFont(StdFont().Bold()).Ink(White).Paper(Blue), + AttrText(path).SetFont(Arial(20).Bold()).Paper(Blue).Ink(White), + AttrText("").SetFont(Arial(20).Bold()).Paper(Blue).Ink(White)); + list.SetLineCy(list.GetCount() - 1, 26); + Vector ln = Split(Sys("svn status " + path), CharFilterCrLf); + bool actions = false; + for(int pass = 0; pass < 2; pass++) + for(int i = 0; i < ln.GetCount(); i++) { + String h = ln[i]; + if(h.GetCount() > 7) { + String file = TrimLeft(h.Mid(7)); + if(IsFullPath(file)) { + actions = true; + h.Trim(7); + bool simple = h.Mid(1, 6) == " "; + int action = simple ? String("MC?!~").Find(h[0]) : -1; + if(h == " S ") + action = REPLACE; + String an; + Color color; + if(action < 0) { + color = Black; + if(simple && h[0] == 'A') + an = "svn add"; + else + if(simple && h[0] == 'D') + an = "svn delete"; + else { + an = h.Mid(0, 7); + color = Gray; + } + } + else { + int q = file.ReverseFind('.'); + if(action == ADD && q >= 0 && (file.Mid(q + 1) == "mine" || + file[q + 1] == 'r' && IsDigit(file[q + 2])) + && FileExists(file.Mid(0, q))) { + action = DELETEC; + an = "Delete"; + color = Black; + } + else { + static const char *as[] = { + "Modify", "Resolved", "Add", "Remove", "Replace" + }; + static Color c[] = { LtBlue, Magenta, Green, LtRed, LtMagenta }; + an = as[action]; + color = c[action]; + } + } + if(pass == action < 0) { + int ii = list.GetCount(); + list.Add(action, file, + action < 0 ? Value(AttrText(an).Ink(color)) : Value(true), + AttrText(" " + file.Mid(path.GetCount() + 1)).Ink(color)); + if(action >= 0) { + list.SetCtrl(ii, 0, revert.Add().SetLabel("Revert\n" + an).NoWantFocus()); + Ctrl& b = diff.Add().SetLabel("Changes..").SizePos().NoWantFocus(); + b <<= THISBACK1(DoDiff, ii); + list.SetCtrl(ii, 2, b); + } + } + } + } + } + if(actions) { + list.Add(MESSAGE, Null, AttrText("Commit message:").SetFont(StdFont().Bold())); + list.SetLineCy(list.GetCount() - 1, (3 * EditField::GetStdHeight()) + 4); + list.SetCtrl(list.GetCount() - 1, 1, message.Add().SetFilter(CharFilterSvnMsg).VSizePos(2, 2).HSizePos()); + int q = msgmap.Find(w.working); + if(q >= 0) { + message.Top() <<= msgmap[q]; + msgmap.Unlink(q); + } + } + else + list.Add(-1, Null, "", AttrText("Nothing to do").SetFont(StdFont().Italic())); + } +} + +void SvnSync::DoDiff(int ii) +{ + String f = list.Get(ii, 1); + if(!IsNull(f)) + RunSvnDiff(f); +} + +void SvnSync::Diff() +{ + int cr = list.GetClickRow(); + if(cr >= 0) + DoDiff(cr); +} + +#ifdef PLATFORM_WIN32 +void sDeleteFolderDeep(const char *dir) +{ + { + FindFile ff(AppendFileName(dir, "*.*")); + while(ff) { + String name = ff.GetName(); + String p = AppendFileName(dir, name); + if(ff.IsFile()) { + SetFileAttributes(p, GetFileAttributes(p) & ~FILE_ATTRIBUTE_READONLY); + FileDelete(p); + } + else + if(ff.IsFolder()) + sDeleteFolderDeep(p); + ff.Next(); + } + } + DirectoryDelete(dir); +} +#else +void sDeleteFolderDeep(const char *path) +{ + DeleteFolderDeep(path); +} +#endif + +void SvnDel(const char *path) +{ + FindFile ff(AppendFileName(path, "*.*")); + while(ff) { + if(ff.IsFolder()) { + String dir = AppendFileName(path, ff.GetName()); + if(ff.GetName() == ".svn") + sDeleteFolderDeep(dir); + else + SvnDel(dir); + } + ff.Next(); + } +} + +void SvnSync::Dir(const char *dir) +{ + setup.Hide(); + works.Add(dir, Null, Null); +} + +void SvnSync::Perform() +{ + if(!CheckSvn()) + return; + const Vector& cl = CommandLine(); + if(cl.GetCount()) + for(int i = 0; i < cl.GetCount(); i++) { + if(cl[i] == "-") { + works.Load(LoadFile(ConfigFile("svnworks"))); + DoSync(); + SaveFile(ConfigFile("svnworks"), works.Save()); + return; + } + String d = GetFullPath(cl[i]); + if(!DirectoryExists(cl[i])) { + Cerr() << cl[i] << " not a directory\n"; + SetExitCode(1); + return; + } + works.Add(d, "", ""); + } + else + works.Add(GetCurrentDirectory(), "", ""); + setup.Hide(); + DoSync(); +} + +void MoveSvn(const String& path, const String& tp) +{ + FindFile ff(AppendFileName(path, "*.*")); + while(ff) { + String nm = ff.GetName(); + String s = AppendFileName(path, nm); + String t = AppendFileName(tp, nm); + if(ff.IsFolder()) + if(nm == ".svn") + FileMove(s, t); + else + MoveSvn(s, t); + ff.Next(); + } +} + +void SvnSync::DoSync() +{ + SyncList(); + msgmap.Sweep(); +again: + if(Execute() != IDOK || list.GetCount() == 0) { + int repoi = 0; + for(int i = 0; i < list.GetCount(); i++) + if(list.Get(i, 0) == MESSAGE) + msgmap.GetAdd(works[repoi++].working) = list.Get(i, 3); + return; + } + bool changes = false; + for(int i = 0; i < list.GetCount(); i++) { + int action = list.Get(i, 0); + Value v = list.Get(i, 2); + if(action == MESSAGE) { + if(changes && IsNull(list.Get(i, 3)) + && !PromptYesNo("Commit message is empty.&Do you want to continue?")) + goto again; + changes = false; + } + else if(action != REPOSITORY && IsNumber(v) && (int)v) + changes = true; + } + SysConsole sys; + int repoi = 0; + int l = 0; + bool commit = false; + while(l < list.GetCount()) { + SvnWork w = works[repoi++]; + l++; + String message; + while(l < list.GetCount()) { + int action = list.Get(l, 0); + String path = list.Get(l, 1); + if(action == MESSAGE && commit) { + String msg = list.Get(l, 3); + if(sys.CheckSystem(SvnCmd("commit", w).Cat() << w.working << " -m \"" << msg << "\"")) + msgmap.GetAdd(w.working) = msg; + l++; + break; + } + if(action == REPOSITORY) + break; + Value v = list.Get(l, 2); + if(IsNumber(v) && (int)v == 0) { + if(action == REPLACE || action == ADD) + DeleteFolderDeep(path); + if(action != ADD) + sys.CheckSystem("svn revert " + path); + } + else { + commit = true; + switch(action) { + case ADD: + SvnDel(path); + sys.CheckSystem("svn add --force " + path); + break; + case REMOVE: + sys.CheckSystem("svn delete " + path); + break; + case CONFLICT: + sys.CheckSystem("svn resolved " + path); + break; + case REPLACE: { + SvnDel(path); + String tp = AppendFileName(GetFileFolder(path), Format(Uuid::Create())); + FileMove(path, tp); + sys.CheckSystem(SvnCmd("update", w).Cat() << ' ' << path); + MoveSvn(path, tp); + sDeleteFolderDeep(path); + FileMove(tp, path); + Vector ln = Split(Sys("svn status " + path), CharFilterCrLf); + for(int l = 0; l < ln.GetCount(); l++) { + String h = ln[l]; + if(h.GetCount() > 7) { + String file = h.Mid(7); + if(IsFullPath(file)) { + h.Trim(7); + if(h == "? ") + sys.CheckSystem("svn add --force " + file); + if(h == "! ") + sys.CheckSystem("svn delete " + file); + } + } + } + } + break; + case DELETEC: + FileDelete(path); + break; + } + } + l++; + } + sys.CheckSystem(SvnCmd("update", w).Cat() << w.working); + } + sys.Perform(); +} + +void SvnSync::SetMsgs(const String& s) +{ + LoadFromString(msgmap, s); +} + +String SvnSync::GetMsgs() +{ + return StoreAsString(msgmap); +} + +bool IsSvnDir(const String& p) +{ + return DirectoryExists(AppendFileName(p, ".svn")) || DirectoryExists(AppendFileName(p, "_svn")); +} + +#ifdef flagMAIN +GUI_APP_MAIN +{ + if(!CheckSvn()) + return; + SvnSync ss; + String mp = ConfigFile("usvn.msg"); + ss.SetMsgs(LoadFile(mp)); + ss.Perform(); + SaveFile(mp, ss.GetMsgs()); +} +#endif