Merge pull request #5073 from mwganson/spreadsheet2

[Spreadsheet] add preference page and 3 import/export parameters
This commit is contained in:
Chris Hennes
2021-09-28 16:14:45 -05:00
committed by GitHub
10 changed files with 518 additions and 4 deletions
+40
View File
@@ -127,6 +127,46 @@ void Sheet::clearAll()
observers.clear();
}
//validate import/export parameters
bool Sheet::getCharsFromPrefs(char &delim, char &quote, char &escape, std::string &errMsg){
bool isValid = true;
ParameterGrp::handle group = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Spreadsheet");
QString delimiter = QString::fromStdString(group->GetASCII("ImportExportDelimiter","tab"));
QString quoteChar = QString::fromStdString(group->GetASCII("ImportExportQuoteCharacter","\""));
QString escapeChar = QString::fromStdString(group->GetASCII("ImportExportEscapeCharacter","\\"));
delim = delimiter.size() == 1 ? delimiter[0].toLatin1() : '\0';
if (delimiter.compare(QLatin1String("tab"), Qt::CaseInsensitive) == 0 || delimiter.compare(QLatin1String("\\t"),Qt::CaseInsensitive) == 0){
delim = '\t';
} else if (delimiter.compare(QLatin1String("comma"), Qt::CaseInsensitive) == 0){
delim = ',';
} else if (delimiter.compare(QLatin1String("semicolon"), Qt::CaseInsensitive) == 0){
delim = ';';
}
if(delim != '\0' && quoteChar.size() == 1 && escapeChar.size() == 1){
quote = quoteChar[0].toLatin1();
escape = escapeChar[0].toLatin1();
} else {
isValid = false;
std::string importExport = errMsg;
std::stringstream errStream;
errStream << "Invalid spreadsheet Import/Export parameter.\n";
if (delim == '\0') {
errStream << "Unrecognized delimiter: " << delimiter.toStdString() << " (recognized tokens: \\t, tab, semicolon, comma, or any single character)\n";
}
if (quoteChar.size() != 1){
errStream << "Invalid quote character: " << quoteChar.toStdString() << " (quote character must be one single character)\n";
}
if (escapeChar.size() != 1){
errStream << "Invalid escape character: " << escapeChar.toStdString() << " (escape character must be one single character)\n";
}
errStream << importExport << " not done.\n";
errMsg = errStream.str();
}
return isValid;
}
/**
* Import a file into the spreadsheet object.
*
+2
View File
@@ -86,6 +86,8 @@ public:
bool importFromFile(const std::string & filename, char delimiter = '\t', char quoteChar = '\0', char escapeChar = '\\');
bool getCharsFromPrefs(char &delimiter, char &quote, char &escape, std::string &errMsg);
bool exportToFile(const std::string & filename, char delimiter = '\t', char quoteChar = '\0', char escapeChar = '\\') const;
bool mergeCells(const App::Range &range);
@@ -41,8 +41,10 @@
#include <Gui/Document.h>
#include <Gui/Application.h>
#include <Gui/BitmapFactory.h>
#include <Gui/WidgetFactory.h>
#include <Gui/Language/Translator.h>
#include <Mod/Spreadsheet/App/Sheet.h>
#include "DlgSettingsImp.h"
#include "Workbench.h"
#include "ViewProviderSpreadsheet.h"
#include "SpreadsheetView.h"
@@ -119,6 +121,9 @@ PyMOD_INIT_FUNC(SpreadsheetGui)
SpreadsheetGui::Workbench::init();
SpreadsheetGui::SheetView::init();
// register preference page
new Gui::PrefPageProducer<SpreadsheetGui::DlgSettingsImp> ("Spreadsheet");
// add resources and reloads the translators
loadSpreadsheetResource();
+23
View File
@@ -64,6 +64,9 @@ SET(SpreadsheetGui_SRCS
${SpreadsheetGui_XML_SRCS}
AppSpreadsheetGui.cpp
Command.cpp
DlgSettings.ui
DlgSettingsImp.cpp
DlgSettingsImp.h
LineEdit.h
LineEdit.cpp
ViewProviderSpreadsheet.cpp
@@ -93,6 +96,26 @@ SET(SpreadsheetGuiIcon_SVG
Resources/icons/SpreadsheetWorkbench.svg
)
set(SpreadsheetGui_MOC_HDRS
DlgSettingsImp.h
)
SOURCE_GROUP("Moc" FILES ${SpreadsheetGui_MOC_SRCS})
SET(Resource_SRCS
${Resource_SRCS}
Resources/Spreadsheet.qrc
)
set(SpreadsheetGui_UIC_SRCS
DlgSettings.ui
)
if (BUILD_QT5)
qt5_wrap_ui(SpreadsheetGui_UIC_HDRS ${SpreadsheetGui_UIC_SRCS})
endif()
add_library(SpreadsheetGui SHARED ${SpreadsheetGui_SRCS} ${SpreadsheetGuiIcon_SVG})
target_link_libraries(SpreadsheetGui ${SpreadsheetGui_LIBS})
+26 -4
View File
@@ -197,9 +197,19 @@ void CmdSpreadsheetImport::activated(int iMsg)
if (!fileName.isEmpty()) {
std::string FeatName = getUniqueObjectName("Spreadsheet");
Sheet * sheet = freecad_dynamic_cast<Sheet>(App::GetApplication().getActiveDocument()->addObject("Spreadsheet::Sheet", FeatName.c_str()));
if (sheet){
char delim, quote, escape;
std::string errMsg = "Import";
bool isValid = sheet->getCharsFromPrefs(delim, quote, escape, errMsg);
sheet->importFromFile(Base::Tools::toStdString(fileName), '\t', '"', '\\');
sheet->execute();
if (isValid){
sheet->importFromFile(fileName.toStdString(), delim, quote, escape);
sheet->execute();
} else {
Base::Console().Error(errMsg.c_str());
return;
}
}
}
}
@@ -240,8 +250,20 @@ void CmdSpreadsheetExport::activated(int iMsg)
QString(),
formatList,
&selectedFilter);
if (!fileName.isEmpty())
sheet->exportToFile(Base::Tools::toStdString(fileName), '\t', '"', '\\');
if (!fileName.isEmpty()){
if (sheet){
char delim, quote, escape;
std::string errMsg = "Export";
bool isValid = sheet->getCharsFromPrefs(delim, quote, escape, errMsg);
if (isValid){
sheet->exportToFile(fileName.toStdString(), delim, quote, escape);
} else {
Base::Console().Error(errMsg.c_str());
return;
}
}
}
}
}
}
+189
View File
@@ -0,0 +1,189 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SpreadsheetGui::DlgSettings</class>
<widget class="QWidget" name="SpreadsheetGui::DlgSettings">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>555</width>
<height>413</height>
</rect>
</property>
<property name="windowTitle">
<string>Spreadsheet</string>
</property>
<widget class="QGroupBox" name="groupBox">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>531</width>
<height>161</height>
</rect>
</property>
<property name="title">
<string>Import/Export Settings</string>
</property>
<widget class="Gui::PrefLineEdit" name="quoteCharLineEdit">
<property name="geometry">
<rect>
<x>156</x>
<y>70</y>
<width>142</width>
<height>25</height>
</rect>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Character used to delimit strings, typically is single quote (') or double quote (&amp;quot;). Must be a single character.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="whatsThis">
<string/>
</property>
<property name="text">
<string>&quot;</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ImportExportQuoteCharacter</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Spreadsheet</cstring>
</property>
</widget>
<widget class="QLabel" name="textLabel">
<property name="geometry">
<rect>
<x>13</x>
<y>33</y>
<width>137</width>
<height>17</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Delimiter Character: </string>
</property>
</widget>
<widget class="Gui::PrefLineEdit" name="escapeCharLineEdit">
<property name="geometry">
<rect>
<x>156</x>
<y>113</y>
<width>142</width>
<height>25</height>
</rect>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Escape character, typically the backslash (\), used to indicate special unprintable characters, e.g. \t = tab. Must be a single character.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>\</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ImportExportEscapeCharacter</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Spreadsheet</cstring>
</property>
</widget>
<widget class="QLabel" name="textLabel3">
<property name="geometry">
<rect>
<x>13</x>
<y>113</y>
<width>124</width>
<height>17</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Escape Character: </string>
</property>
</widget>
<widget class="Gui::PrefComboBox" name="delimiterComboBox">
<property name="geometry">
<rect>
<x>156</x>
<y>33</y>
<width>142</width>
<height>25</height>
</rect>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Character to use as field delimiter. Default is tab, but also commonly used are commas (,) and semicolons (;). Select from the list or enter your own in the field. Must be a single character or the words &lt;span style=&quot; font-style:italic;&quot;&gt;tab&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;comma&lt;/span&gt;, or &lt;span style=&quot; font-style:italic;&quot;&gt;semicolon&lt;/span&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="editable">
<bool>true</bool>
</property>
<property name="currentText">
<string notr="true">tab</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>ImportExportDelimiter</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Spreadsheet</cstring>
</property>
<item>
<property name="text">
<string>tab</string>
</property>
</item>
<item>
<property name="text">
<string>;</string>
</property>
</item>
<item>
<property name="text">
<string>,</string>
</property>
</item>
</widget>
<widget class="QLabel" name="textLabel2">
<property name="geometry">
<rect>
<x>13</x>
<y>70</y>
<width>117</width>
<height>17</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Quote Character: </string>
</property>
</widget>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>Gui::PrefLineEdit</class>
<extends>QLineEdit</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefComboBox</class>
<extends>QComboBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
+111
View File
@@ -0,0 +1,111 @@
/***************************************************************************
* Copyright (c) 2002 Jürgen Riegel <[email protected]> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <QApplication>
#endif
#include "DlgSettingsImp.h"
#include "ui_DlgSettings.h"
#include <Gui/Application.h>
#include <Gui/PrefWidgets.h>
#include <Base/Console.h>
using namespace SpreadsheetGui;
/* TRANSLATOR SpreadsheetGui::DlgSettingsImp */
DlgSettingsImp::DlgSettingsImp( QWidget* parent )
: PreferencePage( parent )
, ui(new Ui_DlgSettings)
{
ui->setupUi(this);
}
/**
* Destroys the object and frees any allocated resources
*/
DlgSettingsImp::~DlgSettingsImp()
{
// no need to delete child widgets, Qt does it all for us
}
void DlgSettingsImp::saveSettings()
{
/** use whatever the user has entered here
* we'll check for validity during import/export
*/
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Spreadsheet");
QString delimiter = ui->delimiterComboBox->currentText();
hGrp->SetASCII("ImportExportDelimiter", delimiter.toStdString().c_str());
ui->quoteCharLineEdit->onSave();
ui->escapeCharLineEdit->onSave();
}
void DlgSettingsImp::loadSettings()
{
/** items "tab", ";", and "," have already been added to the combo box in the .ui file
* we'll recognize a few tokens: comma, semicolon, tab, and \t
*/
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Mod/Spreadsheet");
QString delimiter = QString::fromStdString(hGrp->GetASCII("ImportExportDelimiter", "tab"));
int idx = ui->delimiterComboBox->findText(delimiter, Qt::MatchFixedString);
if(idx != -1){
ui->delimiterComboBox->setCurrentIndex(idx);
} else if(delimiter.compare(QLatin1String("\\t"), Qt::CaseInsensitive) == 0){
idx = ui->delimiterComboBox->findText(QLatin1String("tab"), Qt::MatchFixedString);
ui->delimiterComboBox->setCurrentIndex(idx);
} else if(delimiter.compare(QLatin1String("semicolon"), Qt::CaseInsensitive) == 0){
idx = ui->delimiterComboBox->findText(QLatin1String(";"), Qt::MatchFixedString);
ui->delimiterComboBox->setCurrentIndex(idx);
} else if(delimiter.compare(QLatin1String("comma"), Qt::CaseInsensitive) == 0){
idx = ui->delimiterComboBox->findText(QLatin1String(","), Qt::MatchFixedString);
ui->delimiterComboBox->setCurrentIndex(idx);
} else {
ui->delimiterComboBox->addItem(delimiter);
idx = ui->delimiterComboBox->findText(delimiter, Qt::MatchFixedString);
ui->delimiterComboBox->setCurrentIndex(idx);
}
ui->quoteCharLineEdit->onRestore();
ui->escapeCharLineEdit->onRestore();
}
/**
* Sets the strings of the subwidgets using the current language.
*/
void DlgSettingsImp::changeEvent(QEvent *e)
{
if (e->type() == QEvent::LanguageChange) {
ui->retranslateUi(this);
}
else {
QWidget::changeEvent(e);
}
}
#include "moc_DlgSettingsImp.cpp"
+57
View File
@@ -0,0 +1,57 @@
/***************************************************************************
* Copyright (c) 2021 Mark Ganson <TheMarkster> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#ifndef SPREADSHEETGUI_DLGSETTINGSIMP_H
#define SPREADSHEETGUI_DLGSETTINGSIMP_H
#include <Gui/PropertyPage.h>
#include <memory>
namespace SpreadsheetGui {
class Ui_DlgSettings;
/**
* The DlgSettingsImp class implements a preference page to change settings
* for the Spreadsheet workbench.
* /author TheMarkster, based on work by Jürgen Riegel
*/
class DlgSettingsImp : public Gui::Dialog::PreferencePage
{
Q_OBJECT
public:
DlgSettingsImp( QWidget* parent = 0 );
~DlgSettingsImp();
protected:
void saveSettings();
void loadSettings();
void changeEvent(QEvent *e);
private:
std::unique_ptr<Ui_DlgSettings> ui;
};
} // namespace SpreadsheetGui
#endif // SPREADSHEETGUI_DLGSETTINGSIMP_H
@@ -1,5 +1,6 @@
<RCC>
<qresource prefix="/">
<file>icons/preferences-spreadsheet.svg</file>
<file>icons/Spreadsheet.svg</file>
<file>icons/SpreadsheetController.svg</file>
<file>icons/SpreadsheetImport.svg</file>
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="64px" height="64px" id="svg2860" sodipodi:version="0.32" inkscape:version="0.48.5 r10040" sodipodi:docname="Spreadsheet.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape" version="1.1">
<defs id="defs2862">
<linearGradient inkscape:collect="always" id="linearGradient3783">
<stop style="stop-color:#d3d7cf;stop-opacity:1" offset="0" id="stop3785"/>
<stop style="stop-color:#ffffff;stop-opacity:1" offset="1" id="stop3787"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient3377" id="radialGradient3692" cx="45.883327" cy="28.869568" fx="45.883327" fy="28.869568" r="19.467436" gradientUnits="userSpaceOnUse"/>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient3377" id="radialGradient3703" gradientUnits="userSpaceOnUse" cx="135.38333" cy="97.369568" fx="135.38333" fy="97.369568" r="19.467436" gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)"/>
<linearGradient id="linearGradient3377">
<stop id="stop3379" offset="0" style="stop-color:#faff2b;stop-opacity:1;"/>
<stop id="stop3381" offset="1" style="stop-color:#ffaa00;stop-opacity:1;"/>
</linearGradient>
<radialGradient inkscape:collect="always" xlink:href="#linearGradient3377" id="radialGradient3705" gradientUnits="userSpaceOnUse" cx="148.88333" cy="81.869568" fx="148.88333" fy="81.869568" r="19.467436" gradientTransform="matrix(1.3852588,-0.05136783,0.03705629,0.9993132,-60.392403,7.7040438)"/>
<inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 32 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="64 : 32 : 1" inkscape:persp3d-origin="32 : 21.333333 : 1" id="perspective2868"/>
<linearGradient inkscape:collect="always" xlink:href="#linearGradient3783" id="linearGradient3789" x1="38" y1="58" x2="21" y2="5" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,0.77777777,0,5.1111114)"/>
</defs>
<sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="5.0968312" inkscape:cx="-5.5216512" inkscape:cy="40.95075" inkscape:current-layer="layer1" showgrid="true" inkscape:document-units="px" inkscape:grid-bbox="true" inkscape:window-width="1600" inkscape:window-height="837" inkscape:window-x="0" inkscape:window-y="27" inkscape:window-maximized="1">
<inkscape:grid type="xygrid" id="grid2995" empspacing="2" visible="true" enabled="true" snapvisiblegridlinesonly="true"/>
</sodipodi:namedview>
<metadata id="metadata2865">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
<dc:creator>
<cc:Agent>
<dc:title>[Eivind Kvedalen]</dc:title>
</cc:Agent>
</dc:creator>
<dc:title>Spreadsheet</dc:title>
<dc:date>2013-09-29</dc:date>
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
<dc:publisher>
<cc:Agent>
<dc:title>FreeCAD</dc:title>
</cc:Agent>
</dc:publisher>
<dc:identifier>FreeCAD/src/Mod/Spreadsheet/Gui/Resources/icons/Spreadsheet.svg</dc:identifier>
<dc:rights>
<cc:Agent>
<dc:title>FreeCAD LGPL2+</dc:title>
</cc:Agent>
</dc:rights>
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
<dc:contributor>
<cc:Agent>
<dc:title>[agryson] Alexander Gryson</dc:title>
</cc:Agent>
</dc:contributor>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" inkscape:label="Layer 1" inkscape:groupmode="layer">
<rect style="color:#000000;fill:#ffffff;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3002-9" width="56" height="44" x="4" y="8"/>
<rect style="color:#000000;fill:url(#linearGradient3789);fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" id="rect3002-9-3" width="54" height="42" x="5" y="9"/>
<path style="fill:none;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 3,18 58,0" id="path3790" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
<path style="fill:none;stroke:#2e3436;stroke-width:3.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 22,6 0,48" id="path3792" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
<path style="fill:none;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 3,30 58,0" id="path3794" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
<path style="fill:none;stroke:#2e3436;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" d="m 3,42 58,0" id="path3796" inkscape:connector-curvature="0" sodipodi:nodetypes="cc"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.9 KiB