summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
Diffstat (limited to 'vcl')
-rw-r--r--vcl/source/app/salvtables.cxx227
-rw-r--r--vcl/source/treelist/treelistbox.cxx16
-rw-r--r--vcl/source/window/builder.cxx15
-rw-r--r--vcl/uiconfig/ui/printdialog.ui1
-rw-r--r--vcl/uiconfig/ui/printerdevicepage.ui4
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx389
6 files changed, 613 insertions, 39 deletions
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index ade8338f9946..67ac7ed97986 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -1750,6 +1750,17 @@ IMPL_LINK(SalInstanceEntry, CursorListener, VclWindowEvent&, rEvent, void)
signal_cursor_position();
}
+struct SalInstanceTreeIter : public weld::TreeIter
+{
+ SalInstanceTreeIter(const SalInstanceTreeIter* pOrig)
+ {
+ if (!pOrig)
+ return;
+ iter = pOrig->iter;
+ }
+ SvTreeListEntry* iter;
+};
+
class SalInstanceTreeView : public SalInstanceContainer, public virtual weld::TreeView
{
private:
@@ -1759,19 +1770,26 @@ private:
DECL_LINK(SelectHdl, SvTreeListBox*, void);
DECL_LINK(DoubleClickHdl, SvTreeListBox*, bool);
+ DECL_LINK(ExpandingHdl, SvTreeListBox*, bool);
public:
SalInstanceTreeView(SvTreeListBox* pTreeView, bool bTakeOwnership)
: SalInstanceContainer(pTreeView, bTakeOwnership)
, m_xTreeView(pTreeView)
{
+ m_xTreeView->SetNodeDefaultImages();
m_xTreeView->SetSelectHdl(LINK(this, SalInstanceTreeView, SelectHdl));
m_xTreeView->SetDoubleClickHdl(LINK(this, SalInstanceTreeView, DoubleClickHdl));
+ m_xTreeView->SetExpandingHdl(LINK(this, SalInstanceTreeView, ExpandingHdl));
}
- virtual void insert(int pos, const OUString& rStr, const OUString* pId, const OUString* pIconName, VirtualDevice* pImageSurface) override
+ virtual void insert(weld::TreeIter* pParent, int pos, const OUString& rStr, const OUString* pId,
+ const OUString* pIconName, VirtualDevice* pImageSurface, const OUString* pExpanderName,
+ bool bChildrenOnDemand) override
{
- auto nInsertPos = pos == -1 ? COMBOBOX_APPEND : pos;
+ SalInstanceTreeIter* pVclIter = static_cast<SalInstanceTreeIter*>(pParent);
+ SvTreeListEntry* iter = pVclIter ? pVclIter->iter : nullptr;
+ auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
void* pUserData;
if (pId)
{
@@ -1781,8 +1799,9 @@ public:
else
pUserData = nullptr;
+ SvTreeListEntry* pResult;
if (!pIconName && !pImageSurface)
- m_xTreeView->InsertEntry(rStr, nullptr, false, nInsertPos, pUserData);
+ pResult = m_xTreeView->InsertEntry(rStr, iter, false, nInsertPos, pUserData);
else
{
SvTreeListEntry* pEntry = new SvTreeListEntry;
@@ -1790,7 +1809,20 @@ public:
pEntry->AddItem(o3tl::make_unique<SvLBoxContextBmp>(aImage, aImage, false));
pEntry->AddItem(o3tl::make_unique<SvLBoxString>(rStr));
pEntry->SetUserData(pUserData);
- m_xTreeView->Insert(pEntry, nInsertPos);
+ m_xTreeView->Insert(pEntry, iter, nInsertPos);
+ pResult = pEntry;
+ }
+
+ if (pExpanderName)
+ {
+ Image aImage(createImage(*pExpanderName));
+ m_xTreeView->SetExpandedEntryBmp(pResult, aImage);
+ m_xTreeView->SetCollapsedEntryBmp(pResult, aImage);
+ }
+
+ if (bChildrenOnDemand)
+ {
+ m_xTreeView->InsertEntry("<dummy>", pResult, false, 0, nullptr);
}
}
@@ -1914,6 +1946,157 @@ public:
return m_xTreeView->GetAbsPos(pEntry);
}
+ virtual std::unique_ptr<weld::TreeIter> make_iterator(const weld::TreeIter* pOrig) const override
+ {
+ return std::unique_ptr<weld::TreeIter>(new SalInstanceTreeIter(static_cast<const SalInstanceTreeIter*>(pOrig)));
+ }
+
+ virtual void copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const override
+ {
+ const SalInstanceTreeIter& rVclSource(static_cast<const SalInstanceTreeIter&>(rSource));
+ SalInstanceTreeIter& rVclDest(static_cast<SalInstanceTreeIter&>(rDest));
+ rVclDest.iter = rVclSource.iter;
+ }
+
+ virtual bool get_selected(weld::TreeIter* pIter) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->FirstSelected();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+ }
+
+ virtual bool get_cursor(weld::TreeIter* pIter) const override
+ {
+ SvTreeListEntry* pEntry = m_xTreeView->GetCurEntry();
+ auto pVclIter = static_cast<SalInstanceTreeIter*>(pIter);
+ if (pVclIter)
+ pVclIter->iter = pEntry;
+ return pEntry != nullptr;
+ }
+
+ virtual void set_cursor(const weld::TreeIter& rIter) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->SetCurEntry(rVclIter.iter);
+ }
+
+ virtual bool get_iter_first(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->GetEntry(0);
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual bool iter_next_sibling(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = rVclIter.iter->NextSibling();
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual bool iter_next(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->Next(rVclIter.iter);
+ if (rVclIter.iter && m_xTreeView->GetEntryText(rVclIter.iter) == "<dummy>")
+ return iter_next(rVclIter);
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual bool iter_children(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->FirstChild(rVclIter.iter);
+ bool bRet = rVclIter.iter != nullptr;
+ if (bRet)
+ {
+ //on-demand dummy entry doesn't count
+ return m_xTreeView->GetEntryText(rVclIter.iter) != "<dummy>";
+ }
+ return bRet;
+ }
+
+ virtual bool iter_parent(weld::TreeIter& rIter) const override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ rVclIter.iter = m_xTreeView->GetParent(rVclIter.iter);
+ return rVclIter.iter != nullptr;
+ }
+
+ virtual void remove(const weld::TreeIter& rIter) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->RemoveEntry(rVclIter.iter);
+ }
+
+ virtual void select(const weld::TreeIter& rIter) override
+ {
+ assert(m_xTreeView->IsUpdateMode() && "don't select when frozen");
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->Select(rVclIter.iter, true);
+ enable_notify_events();
+ }
+
+ virtual void unselect(const weld::TreeIter& rIter) override
+ {
+ assert(m_xTreeView->IsUpdateMode() && "don't unselect when frozen");
+ disable_notify_events();
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ m_xTreeView->Select(rVclIter.iter, false);
+ enable_notify_events();
+ }
+
+ virtual int get_iter_depth(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->GetModel()->GetDepth(rVclIter.iter);
+ }
+
+ virtual bool iter_has_child(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return rVclIter.iter->HasChildren();
+ }
+
+ virtual bool get_row_expanded(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->IsExpanded(rVclIter.iter);
+ }
+
+ virtual void expand_row(weld::TreeIter& rIter) override
+ {
+ SalInstanceTreeIter& rVclIter = static_cast<SalInstanceTreeIter&>(rIter);
+ if (!m_xTreeView->IsExpanded(rVclIter.iter) && signal_expanding(rIter))
+ m_xTreeView->Expand(rVclIter.iter);
+ }
+
+ virtual OUString get_text(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ return m_xTreeView->GetEntryText(rVclIter.iter);
+ }
+
+ virtual OUString get_id(const weld::TreeIter& rIter) const override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ const OUString* pStr = static_cast<const OUString*>(rVclIter.iter->GetUserData());
+ if (pStr)
+ return *pStr;
+ return OUString();
+ }
+
+ virtual void set_expander_image(const weld::TreeIter& rIter, const OUString& rImage) override
+ {
+ const SalInstanceTreeIter& rVclIter = static_cast<const SalInstanceTreeIter&>(rIter);
+ Image aImage(createImage(rImage));
+ m_xTreeView->SetExpandedEntryBmp(rVclIter.iter, aImage);
+ m_xTreeView->SetCollapsedEntryBmp(rVclIter.iter, aImage);
+ }
+
virtual void set_selection_mode(bool bMultiple) override
{
m_xTreeView->SetSelectionMode(bMultiple ? SelectionMode::Multiple : SelectionMode::Single);
@@ -1941,6 +2124,7 @@ public:
virtual ~SalInstanceTreeView() override
{
+ m_xTreeView->SetExpandingHdl(Link<SvTreeListBox*, bool>());
m_xTreeView->SetDoubleClickHdl(Link<SvTreeListBox*, bool>());
m_xTreeView->SetSelectHdl(Link<SvTreeListBox*, void>());
}
@@ -1961,6 +2145,41 @@ IMPL_LINK_NOARG(SalInstanceTreeView, DoubleClickHdl, SvTreeListBox*, bool)
return false;
}
+IMPL_LINK_NOARG(SalInstanceTreeView, ExpandingHdl, SvTreeListBox*, bool)
+{
+ SvTreeListEntry* pEntry = m_xTreeView->GetHdlEntry();
+ if (m_xTreeView->IsExpanded(pEntry))
+ {
+ //collapsing;
+ return true;
+ }
+
+ // if there's a preexisting placeholder child, required to make this
+ // potentially expandable in the first place, now we remove it
+ bool bPlaceHolder = false;
+ if (pEntry->HasChildren())
+ {
+ auto pChild = m_xTreeView->FirstChild(pEntry);
+ if (m_xTreeView->GetEntryText(pChild) == "<dummy>")
+ {
+ m_xTreeView->RemoveEntry(pChild);
+ bPlaceHolder = true;
+ }
+ }
+
+ SalInstanceTreeIter aIter(nullptr);
+ aIter.iter = pEntry;
+ bool bRet = signal_expanding(aIter);
+
+ //expand disallowed, restore placeholder
+ if (!bRet && bPlaceHolder)
+ {
+ m_xTreeView->InsertEntry("<dummy>", pEntry, false, 0, nullptr);
+ }
+
+ return bRet;
+}
+
class SalInstanceSpinButton : public SalInstanceEntry, public virtual weld::SpinButton
{
private:
diff --git a/vcl/source/treelist/treelistbox.cxx b/vcl/source/treelist/treelistbox.cxx
index a581fd5172e6..e51363bd2861 100644
--- a/vcl/source/treelist/treelistbox.cxx
+++ b/vcl/source/treelist/treelistbox.cxx
@@ -2137,9 +2137,11 @@ bool SvTreeListBox::Expand( SvTreeListEntry* pParent )
if( pParent->HasChildrenOnDemand() )
RequestingChildren( pParent );
- if( pParent->HasChildren() )
+ bool bExpandAllowed = pParent->HasChildren() && ExpandingHdl();
+ // double check if the expander callback ended up removing all children
+ if (pParent->HasChildren())
{
- if( ExpandingHdl() )
+ if (bExpandAllowed)
{
bExpanded = true;
ExpandListEntry( pParent );
@@ -3649,7 +3651,7 @@ bool SvTreeListBox::set_property(const OString &rKey, const OUString &rValue)
{
set_min_width_in_chars(rValue.toInt32());
}
- if (rKey == "enable-tree-lines")
+ else if (rKey == "enable-tree-lines")
{
auto nStyle = GetStyle();
nStyle &= ~(WB_HASLINES | WB_HASLINESATROOT);
@@ -3657,6 +3659,14 @@ bool SvTreeListBox::set_property(const OString &rKey, const OUString &rValue)
nStyle |= (WB_HASLINES | WB_HASLINESATROOT);
SetStyle(nStyle);
}
+ else if (rKey == "show-expanders")
+ {
+ auto nStyle = GetStyle();
+ nStyle &= ~(WB_HASBUTTONS | WB_HASBUTTONSATROOT);
+ if (toBool(rValue))
+ nStyle |= (WB_HASBUTTONS | WB_HASBUTTONSATROOT);
+ SetStyle(nStyle);
+ }
else
return Control::set_property(rKey, rValue);
return true;
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index b2dbeba41233..edb7398b69a3 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -1892,7 +1892,7 @@ VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OString &
xWindow = VclPtr<ListBox>::Create(pRealParent, nWinStyle);
else
{
- VclPtrInstance<SvTreeListBox> xBox(pRealParent, nWinStyle);
+ VclPtrInstance<SvTreeListBox> xBox(pRealParent, nWinStyle | WB_HASBUTTONS | WB_HASBUTTONSATROOT);
xBox->SetNoAutoCurEntry(true);
xBox->SetHighlightRange(); // select over the whole width
xWindow = xBox;
@@ -2909,10 +2909,9 @@ void VclBuilder::handleRow(xmlreader::XmlReader &reader, const OString &rID)
m_pParserState->m_aModels[rID].m_aEntries.push_back(aRow);
}
-void VclBuilder::handleListStore(xmlreader::XmlReader &reader, const OString &rID)
+void VclBuilder::handleListStore(xmlreader::XmlReader &reader, const OString &rID, const OString &rClass)
{
int nLevel = 1;
- sal_Int32 nRowIndex = 0;
while(true)
{
@@ -2929,8 +2928,10 @@ void VclBuilder::handleListStore(xmlreader::XmlReader &reader, const OString &rI
{
if (name.equals("row"))
{
- handleRow(reader, rID);
- nRowIndex++;
+ bool bNotTreeStore = rClass != "GtkTreeStore";
+ if (bNotTreeStore)
+ handleRow(reader, rID);
+ assert(bNotTreeStore && "gtk, as the time of writing, doesn't support data in GtkTreeStore serialization");
}
else
++nLevel;
@@ -3433,9 +3434,9 @@ VclPtr<vcl::Window> VclBuilder::handleObject(vcl::Window *pParent, xmlreader::Xm
}
}
- if (sClass == "GtkListStore")
+ if (sClass == "GtkListStore" || sClass == "GtkTreeStore")
{
- handleListStore(reader, sID);
+ handleListStore(reader, sID, sClass);
return nullptr;
}
else if (sClass == "GtkMenu")
diff --git a/vcl/uiconfig/ui/printdialog.ui b/vcl/uiconfig/ui/printdialog.ui
index 2c2061c22c43..d832944052cc 100644
--- a/vcl/uiconfig/ui/printdialog.ui
+++ b/vcl/uiconfig/ui/printdialog.ui
@@ -456,6 +456,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
+ <property name="show_expanders">False</property>
<child internal-child="selection">
<object class="GtkTreeSelection" id="treeview-selection"/>
</child>
diff --git a/vcl/uiconfig/ui/printerdevicepage.ui b/vcl/uiconfig/ui/printerdevicepage.ui
index 1dc801f78ea9..48ea728fb201 100644
--- a/vcl/uiconfig/ui/printerdevicepage.ui
+++ b/vcl/uiconfig/ui/printerdevicepage.ui
@@ -2,7 +2,7 @@
<!-- Generated with glade 3.20.4 -->
<interface domain="vcl">
<requires lib="gtk+" version="3.18"/>
- <object class="GtkListStore" id="liststore1">
+ <object class="GtkTreeStore" id="liststore1">
<columns>
<!-- column-name text -->
<column type="gchararray"/>
@@ -10,7 +10,7 @@
<column type="gchararray"/>
</columns>
</object>
- <object class="GtkListStore" id="liststore2">
+ <object class="GtkTreeStore" id="liststore2">
<columns>
<!-- column-name text -->
<column type="gchararray"/>
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index 2ffe595cb223..7e613bd202d1 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -4023,6 +4023,89 @@ namespace
}
}
}
+
+ GdkPixbuf* getPixbuf(const OUString& rIconName)
+ {
+ GdkPixbuf* pixbuf = nullptr;
+
+ if (rIconName.lastIndexOf('.') != rIconName.getLength() - 4)
+ {
+ assert((rIconName== "dialog-warning" || rIconName== "dialog-error" || rIconName== "dialog-information") &&
+ "unknown stock image");
+
+ GError *error = nullptr;
+ GtkIconTheme *icon_theme = gtk_icon_theme_get_default();
+ pixbuf = gtk_icon_theme_load_icon(icon_theme, OUStringToOString(rIconName, RTL_TEXTENCODING_UTF8).getStr(),
+ 16, GTK_ICON_LOOKUP_USE_BUILTIN, &error);
+ }
+ else
+ {
+ const AllSettings& rSettings = Application::GetSettings();
+ pixbuf = load_icon_by_name(rIconName,
+ rSettings.GetStyleSettings().DetermineIconTheme(),
+ rSettings.GetUILanguageTag().getBcp47());
+ }
+
+ return pixbuf;
+ }
+
+ void insert_row(GtkTreeStore* pTreeStore, GtkTreeIter& iter, GtkTreeIter* parent, int pos, const OUString* pId, const OUString& rText,
+ const OUString* pIconName, VirtualDevice* pDevice, const OUString* pExpanderName)
+ {
+ if (!pIconName && !pDevice)
+ {
+ gtk_tree_store_insert_with_values(pTreeStore, &iter, parent, pos,
+ 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(),
+ 1, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8).getStr(),
+ -1);
+ }
+ else
+ {
+ if (pIconName)
+ {
+ GdkPixbuf* pixbuf = getPixbuf(*pIconName);
+
+ gtk_tree_store_insert_with_values(pTreeStore, &iter, parent, pos,
+ 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(),
+ 1, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8).getStr(),
+ 2, pixbuf,
+ -1);
+
+ if (pixbuf)
+ g_object_unref(pixbuf);
+ }
+ else
+ {
+ cairo_surface_t* surface = get_underlying_cairo_surface(*pDevice);
+
+ Size aSize(pDevice->GetOutputSizePixel());
+ cairo_surface_t* target = cairo_surface_create_similar(surface,
+ cairo_surface_get_content(surface),
+ aSize.Width(),
+ aSize.Height());
+
+ cairo_t* cr = cairo_create(target);
+ cairo_set_source_surface(cr, surface, 0, 0);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ gtk_tree_store_insert_with_values(pTreeStore, &iter, parent, pos,
+ 0, OUStringToOString(rText, RTL_TEXTENCODING_UTF8).getStr(),
+ 1, !pId ? nullptr : OUStringToOString(*pId, RTL_TEXTENCODING_UTF8).getStr(),
+ 3, target,
+ -1);
+ cairo_surface_destroy(target);
+ }
+ }
+
+ if (pExpanderName)
+ {
+ GdkPixbuf* pixbuf = getPixbuf(*pExpanderName);
+ gtk_tree_store_set(pTreeStore, &iter, 4, pixbuf, -1);
+ if (pixbuf)
+ g_object_unref(pixbuf);
+ }
+ }
}
namespace
@@ -4042,14 +4125,26 @@ namespace
}
}
+struct GtkInstanceTreeIter : public weld::TreeIter
+{
+ GtkInstanceTreeIter(const GtkInstanceTreeIter* pOrig)
+ {
+ if (!pOrig)
+ return;
+ iter = pOrig->iter;
+ }
+ GtkTreeIter iter;
+};
+
class GtkInstanceTreeView : public GtkInstanceContainer, public virtual weld::TreeView
{
private:
GtkTreeView* m_pTreeView;
- GtkListStore* m_pListStore;
+ GtkTreeStore* m_pTreeStore;
std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter;
gulong m_nChangedSignalId;
gulong m_nRowActivatedSignalId;
+ gulong m_nTestExpandRowSignalId;
DECL_LINK(async_signal_changed, void*, void);
@@ -4075,7 +4170,7 @@ private:
OUString get(int pos, int col) const
{
OUString sRet;
- GtkTreeModel *pModel = GTK_TREE_MODEL(m_pListStore);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
GtkTreeIter iter;
if (gtk_tree_model_iter_nth_child(pModel, &iter, nullptr, pos))
{
@@ -4087,53 +4182,99 @@ private:
return sRet;
}
+ static gboolean signalTestExpandRow(GtkTreeView*, GtkTreeIter* iter, GtkTreePath*, gpointer widget)
+ {
+ GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
+ return !pThis->signal_test_expand_row(*iter);
+ }
+
+ bool signal_test_expand_row(GtkTreeIter& iter)
+ {
+ GtkInstanceTreeIter aIter(nullptr);
+
+ // if there's a preexisting placeholder child, required to make this
+ // potentially expandable in the first place, now we remove it
+ bool bPlaceHolder = false;
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreeIter tmp;
+ if (gtk_tree_model_iter_children(pModel, &tmp, &iter))
+ {
+ aIter.iter = tmp;
+ if (get_text(aIter) == "<dummy>")
+ {
+ gtk_tree_store_remove(m_pTreeStore, &tmp);
+ bPlaceHolder = true;
+ }
+ }
+
+ aIter.iter = iter;
+ bool bRet = signal_expanding(aIter);
+
+ //expand disallowed, restore placeholder
+ if (!bRet && bPlaceHolder)
+ {
+ GtkTreeIter subiter;
+ insert_row(m_pTreeStore, subiter, &iter, -1, nullptr, "<dummy>", nullptr, nullptr, nullptr);
+ }
+
+ return bRet;
+ }
+
public:
GtkInstanceTreeView(GtkTreeView* pTreeView, bool bTakeOwnership)
: GtkInstanceContainer(GTK_CONTAINER(pTreeView), bTakeOwnership)
, m_pTreeView(pTreeView)
- , m_pListStore(GTK_LIST_STORE(gtk_tree_view_get_model(m_pTreeView)))
+ , m_pTreeStore(GTK_TREE_STORE(gtk_tree_view_get_model(m_pTreeView)))
, m_nChangedSignalId(g_signal_connect(gtk_tree_view_get_selection(pTreeView), "changed",
G_CALLBACK(signalChanged), this))
, m_nRowActivatedSignalId(g_signal_connect(pTreeView, "row-activated", G_CALLBACK(signalRowActivated), this))
+ , m_nTestExpandRowSignalId(g_signal_connect(pTreeView, "test-expand-row", G_CALLBACK(signalTestExpandRow), this))
{
}
- virtual void insert(int pos, const OUString& rText, const OUString* pId, const OUString* pIconName, VirtualDevice* pImageSurface) override
+ virtual void insert(weld::TreeIter* pParent, int pos, const OUString& rText, const OUString* pId, const OUString* pIconName,
+ VirtualDevice* pImageSurface, const OUString* pExpanderName, bool bChildrenOnDemand) override
{
disable_notify_events();
GtkTreeIter iter;
- insert_row(m_pListStore, iter, pos, pId, rText, pIconName, pImageSurface);
+ GtkInstanceTreeIter* pGtkIter = static_cast<GtkInstanceTreeIter*>(pParent);
+ insert_row(m_pTreeStore, iter, pGtkIter ? &pGtkIter->iter : nullptr, pos, pId, rText, pIconName, pImageSurface, pExpanderName);
+ if (bChildrenOnDemand)
+ {
+ GtkTreeIter subiter;
+ insert_row(m_pTreeStore, subiter, &iter, -1, nullptr, "<dummy>", nullptr, nullptr, nullptr);
+ }
enable_notify_events();
}
virtual void set_font_color(int pos, const Color& rColor) const override
{
GtkTreeIter iter;
- gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos);
+ gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pTreeStore), &iter, nullptr, pos);
GdkRGBA aColor{rColor.GetRed()/255.0, rColor.GetGreen()/255.0, rColor.GetBlue()/255.0, 0};
- gtk_list_store_set(m_pListStore, &iter, 4, &aColor, -1);
+ gtk_tree_store_set(m_pTreeStore, &iter, 4, &aColor, -1);
}
virtual void remove(int pos) override
{
disable_notify_events();
GtkTreeIter iter;
- gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos);
- gtk_list_store_remove(m_pListStore, &iter);
+ gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pTreeStore), &iter, nullptr, pos);
+ gtk_tree_store_remove(m_pTreeStore, &iter);
enable_notify_events();
}
virtual int find_text(const OUString& rText) const override
{
Search aSearch(rText, 0);
- gtk_tree_model_foreach(GTK_TREE_MODEL(m_pListStore), foreach_find, &aSearch);
+ gtk_tree_model_foreach(GTK_TREE_MODEL(m_pTreeStore), foreach_find, &aSearch);
return aSearch.index;
}
virtual int find_id(const OUString& rId) const override
{
Search aSearch(rId, 1);
- gtk_tree_model_foreach(GTK_TREE_MODEL(m_pListStore), foreach_find, &aSearch);
+ gtk_tree_model_foreach(GTK_TREE_MODEL(m_pTreeStore), foreach_find, &aSearch);
return aSearch.index;
}
@@ -4142,14 +4283,16 @@ public:
if (pos == before)
return;
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+
disable_notify_events();
GtkTreeIter iter;
- gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &iter, nullptr, pos);
+ gtk_tree_model_iter_nth_child(pModel, &iter, nullptr, pos);
GtkTreeIter position;
- gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(m_pListStore), &position, nullptr, before);
+ gtk_tree_model_iter_nth_child(pModel, &position, nullptr, before);
- gtk_list_store_move_before(m_pListStore, &iter, &position);
+ gtk_tree_store_move_before(m_pTreeStore, &iter, &position);
enable_notify_events();
}
@@ -4163,7 +4306,7 @@ public:
virtual void clear() override
{
disable_notify_events();
- gtk_list_store_clear(m_pListStore);
+ gtk_tree_store_clear(m_pTreeStore);
enable_notify_events();
}
@@ -4172,14 +4315,14 @@ public:
m_xSorter.reset(new comphelper::string::NaturalStringSorter(
::comphelper::getProcessComponentContext(),
Application::GetSettings().GetUILanguageTag().getLocale()));
- GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pListStore);
+ GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeStore);
gtk_tree_sortable_set_sort_func(pSortable, 0, sort_func, m_xSorter.get(), nullptr);
gtk_tree_sortable_set_sort_column_id(pSortable, 0, GTK_SORT_ASCENDING);
}
virtual int n_children() const override
{
- return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_pListStore), nullptr);
+ return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(m_pTreeStore), nullptr);
}
virtual void select(int pos) override
@@ -4257,15 +4400,214 @@ public:
return nRet;
}
+ virtual std::unique_ptr<weld::TreeIter> make_iterator(const weld::TreeIter* pOrig) const override
+ {
+ return std::unique_ptr<weld::TreeIter>(new GtkInstanceTreeIter(static_cast<const GtkInstanceTreeIter*>(pOrig)));
+ }
+
+ virtual void copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const override
+ {
+ const GtkInstanceTreeIter& rGtkSource(static_cast<const GtkInstanceTreeIter&>(rSource));
+ GtkInstanceTreeIter& rGtkDest(static_cast<GtkInstanceTreeIter&>(rDest));
+ rGtkDest.iter = rGtkSource.iter;
+ }
+
+ virtual bool get_selected(weld::TreeIter* pIter) const override
+ {
+ GtkInstanceTreeIter* pGtkIter = static_cast<GtkInstanceTreeIter*>(pIter);
+ return gtk_tree_selection_get_selected(gtk_tree_view_get_selection(m_pTreeView), nullptr, pGtkIter ? &pGtkIter->iter : nullptr);
+ }
+
+ virtual bool get_cursor(weld::TreeIter* pIter) const override
+ {
+ GtkInstanceTreeIter* pGtkIter = static_cast<GtkInstanceTreeIter*>(pIter);
+ GtkTreePath* path;
+ gtk_tree_view_get_cursor(m_pTreeView, &path, nullptr);
+ if (pGtkIter && path)
+ {
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ gtk_tree_model_get_iter(pModel, &pGtkIter->iter, path);
+ }
+ return path != nullptr;
+ }
+
+ virtual void set_cursor(const weld::TreeIter& rIter) override
+ {
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreePath* path = gtk_tree_model_get_path(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
+ gtk_tree_view_set_cursor(m_pTreeView, path, nullptr, false);
+ gtk_tree_path_free(path);
+ }
+
+ virtual bool get_iter_first(weld::TreeIter& rIter) const override
+ {
+ GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ return gtk_tree_model_get_iter_first(pModel, &rGtkIter.iter);
+ }
+
+ virtual bool iter_next_sibling(weld::TreeIter& rIter) const override
+ {
+ GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ return gtk_tree_model_iter_next(pModel, &rGtkIter.iter);
+ }
+
+ virtual bool iter_next(weld::TreeIter& rIter) const override
+ {
+ GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreeIter iter = rGtkIter.iter;
+ if (iter_children(rGtkIter))
+ return true;
+ GtkTreeIter tmp = iter;
+ if (gtk_tree_model_iter_next(pModel, &tmp))
+ {
+ rGtkIter.iter = tmp;
+ return true;
+ }
+ if (!gtk_tree_model_iter_parent(pModel, &tmp, &iter))
+ return false;
+ tmp = iter;
+ if (gtk_tree_model_iter_next(pModel, &tmp))
+ {
+ rGtkIter.iter = tmp;
+ return true;
+ }
+ return false;
+ }
+
+ virtual bool iter_children(weld::TreeIter& rIter) const override
+ {
+ GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreeIter tmp;
+ gboolean ret = gtk_tree_model_iter_children(pModel, &tmp, &rGtkIter.iter);
+ rGtkIter.iter = tmp;
+ if (ret)
+ {
+ //on-demand dummy entry doesn't count
+ return get_text(rGtkIter) != "<dummy>";
+ }
+ return ret;
+ }
+
+ virtual bool iter_parent(weld::TreeIter& rIter) const override
+ {
+ GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreeIter tmp;
+ auto ret = gtk_tree_model_iter_parent(pModel, &tmp, &rGtkIter.iter);
+ rGtkIter.iter = tmp;
+ return ret;
+ }
+
+ virtual void remove(const weld::TreeIter& rIter) override
+ {
+ disable_notify_events();
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ gtk_tree_store_remove(m_pTreeStore, const_cast<GtkTreeIter*>(&rGtkIter.iter));
+ enable_notify_events();
+ }
+
+ virtual void select(const weld::TreeIter& rIter) override
+ {
+ assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen");
+ disable_notify_events();
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ gtk_tree_selection_select_iter(gtk_tree_view_get_selection(m_pTreeView), const_cast<GtkTreeIter*>(&rGtkIter.iter));
+ enable_notify_events();
+ }
+
+ virtual void unselect(const weld::TreeIter& rIter) override
+ {
+ assert(gtk_tree_view_get_model(m_pTreeView) && "don't select when frozen");
+ disable_notify_events();
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ gtk_tree_selection_unselect_iter(gtk_tree_view_get_selection(m_pTreeView), const_cast<GtkTreeIter*>(&rGtkIter.iter));
+ enable_notify_events();
+ }
+
+ virtual int get_iter_depth(const weld::TreeIter& rIter) const override
+ {
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreePath* path = gtk_tree_model_get_path(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
+ int ret = gtk_tree_path_get_depth(path) - 1;
+ gtk_tree_path_free(path);
+ return ret;
+ }
+
+ virtual bool iter_has_child(const weld::TreeIter& rIter) const override
+ {
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ return gtk_tree_model_iter_has_child(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
+ }
+
+ virtual bool get_row_expanded(const weld::TreeIter& rIter) const override
+ {
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreePath* path = gtk_tree_model_get_path(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter));
+ bool ret = gtk_tree_view_row_expanded(m_pTreeView, path);
+ gtk_tree_path_free(path);
+ return ret;
+ }
+
+ virtual void expand_row(weld::TreeIter& rIter) override
+ {
+ GtkInstanceTreeIter& rGtkIter = static_cast<GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ GtkTreePath* path = gtk_tree_model_get_path(pModel, &rGtkIter.iter);
+ if (!gtk_tree_view_row_expanded(m_pTreeView, path))
+ gtk_tree_view_expand_row(m_pTreeView, path, false);
+ gtk_tree_path_free(path);
+ }
+
+ virtual OUString get_text(const weld::TreeIter& rIter) const override
+ {
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ gchar* pStr;
+ gtk_tree_model_get(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter), 0, &pStr, -1);
+ OUString sRet(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
+ g_free(pStr);
+ return sRet;
+ }
+
+ virtual OUString get_id(const weld::TreeIter& rIter) const override
+ {
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
+ gchar* pStr;
+ gtk_tree_model_get(pModel, const_cast<GtkTreeIter*>(&rGtkIter.iter), 1, &pStr, -1);
+ OUString sRet(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
+ g_free(pStr);
+ return sRet;
+ }
+
+ virtual void set_expander_image(const weld::TreeIter& rIter, const OUString& rExpanderName) override
+ {
+ const GtkInstanceTreeIter& rGtkIter = static_cast<const GtkInstanceTreeIter&>(rIter);
+ disable_notify_events();
+ GdkPixbuf* pixbuf = getPixbuf(rExpanderName);
+ gtk_tree_store_set(m_pTreeStore, const_cast<GtkTreeIter*>(&rGtkIter.iter), 4, pixbuf, -1);
+ if (pixbuf)
+ g_object_unref(pixbuf);
+ enable_notify_events();
+ }
+
virtual void freeze() override
{
disable_notify_events();
- g_object_ref(m_pListStore);
+ g_object_ref(m_pTreeStore);
GtkInstanceContainer::freeze();
gtk_tree_view_set_model(m_pTreeView, nullptr);
if (m_xSorter)
{
- GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pListStore);
+ GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeStore);
gtk_tree_sortable_set_sort_column_id(pSortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
}
enable_notify_events();
@@ -4276,12 +4618,12 @@ public:
disable_notify_events();
if (m_xSorter)
{
- GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pListStore);
+ GtkTreeSortable* pSortable = GTK_TREE_SORTABLE(m_pTreeStore);
gtk_tree_sortable_set_sort_column_id(pSortable, 0, GTK_SORT_ASCENDING);
}
- gtk_tree_view_set_model(m_pTreeView, GTK_TREE_MODEL(m_pListStore));
+ gtk_tree_view_set_model(m_pTreeView, GTK_TREE_MODEL(m_pTreeStore));
GtkInstanceContainer::thaw();
- g_object_unref(m_pListStore);
+ g_object_unref(m_pTreeStore);
enable_notify_events();
}
@@ -4371,8 +4713,9 @@ public:
virtual ~GtkInstanceTreeView() override
{
- g_signal_handler_disconnect(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId);
+ g_signal_handler_disconnect(m_pTreeView, m_nTestExpandRowSignalId);
g_signal_handler_disconnect(m_pTreeView, m_nRowActivatedSignalId);
+ g_signal_handler_disconnect(gtk_tree_view_get_selection(m_pTreeView), m_nChangedSignalId);
}
};