include/sfx2/sfxsids.hrc                                          |    3 
 officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu |    8 
 officecfg/registry/schema/org/openoffice/Office/Calc.xcs          |   30 
 sc/Library_sc.mk                                                  |    1 
 sc/UIConfig_scalc.mk                                              |    1 
 sc/inc/sc.hrc                                                     |    1 
 sc/inc/strings.hrc                                                |    4 
 sc/sdi/scalc.sdi                                                  |   26 
 sc/sdi/tabvwsh.sdi                                                |    1 
 sc/source/ui/inc/duplicaterecordsdlg.hxx                          |   75 ++
 sc/source/ui/inc/tabvwsh.hxx                                      |    8 
 sc/source/ui/miscdlgs/duplicaterecordsdlg.cxx                     |  214 ++++++
 sc/source/ui/view/tabvwsh3.cxx                                    |  112 +++
 sc/source/ui/view/tabvwsh4.cxx                                    |  239 
+++++++
 sc/uiconfig/scalc/menubar/menubar.xml                             |    1 
 sc/uiconfig/scalc/ui/duplicaterecordsdlg.ui                       |  339 
++++++++++
 16 files changed, 1062 insertions(+), 1 deletion(-)

New commits:
commit 29fd68bb682006ccaa5aaed516c064b5b6368463
Author:     Sahil Gautam <me.sahilgau...@gmail.com>
AuthorDate: Tue Sep 24 23:57:22 2024 +0530
Commit:     Heiko Tietze <heiko.tie...@documentfoundation.org>
CommitDate: Fri Sep 27 15:22:46 2024 +0200

    tdf#85976 [RFE] Add a "Remove Duplicate Records" command
    
    Add a "Remove Duplicate Records" entry under Calc > menu Data
    to remove duplicate records from a rectangular selection
    of cells in Calc.
    
    Change-Id: Ic8340d7f1e19461ef3666fd2ef65294b73577d5c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160685
    Reviewed-by: Heiko Tietze <heiko.tie...@documentfoundation.org>
    Tested-by: Jenkins

diff --git a/include/sfx2/sfxsids.hrc b/include/sfx2/sfxsids.hrc
index a4aad72cf96a..411a00782c02 100644
--- a/include/sfx2/sfxsids.hrc
+++ b/include/sfx2/sfxsids.hrc
@@ -684,7 +684,8 @@ class SvxZoomItem;
 #define FN_PARAM_4                          (FN_PARAM+63)
 #define FN_PARAM_5                          (FN_PARAM+64)
 #define FN_PARAM_6                          (FN_PARAM+65)
-#define FN_NOUPDATE                         
TypedWhichId<SfxBoolItem>(FN_PARAM+66)
+#define FN_PARAM_7                          (FN_PARAM+66)
+#define FN_NOUPDATE                         
TypedWhichId<SfxBoolItem>(FN_PARAM+67)
 #define FN_FAX                              (SID_SW_START + 28)   /* Fax */
 
 #define SID_KEYFUNC_START                   (SID_SC_START + 521)
diff --git a/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu 
b/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
index 16703019b5c5..2f9724f2f50b 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/CalcCommands.xcu
@@ -1378,6 +1378,14 @@
           <value>1</value>
         </prop>
       </node>
+      <node oor:name=".uno:HandleDuplicateRecords" oor:op="replace">
+        <prop oor:name="Label" oor:type="xs:string">
+        <value xml:lang="en-US">Duplicate Records...</value>
+        </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
+      </node>
       <node oor:name=".uno:ViewColumnRowHighlighting" oor:op="replace">
         <prop oor:name="Label" oor:type="xs:string">
           <value xml:lang="en-US">Column/Row Highlighting</value>
diff --git a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
index 1a5849279ee9..42eeae9d25c8 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
@@ -1791,6 +1791,36 @@
       <info>
         <desc>Contains miscellaneous settings.</desc>
       </info>
+      <group oor:name="HandleDuplicateRecords">
+        <info>
+          <desc>Defines the settings for 'handle duplicate records' 
dialog.</desc>
+          <label>Handle duplicate records settings</label>
+        </info>
+        <prop oor:name="DataIncludesHeaders" oor:type="xs:boolean" 
oor:nillable="false">
+          <!-- UIHints: Data - Duplicate Records... -->
+          <info>
+            <desc>Indicates whether selected data includes headers in the 
'handle duplicate records' dialog.</desc>
+            <label>Data includes row/column headers</label>
+          </info>
+          <value>false</value>
+        </prop>
+        <prop oor:name="RemoveDuplicateRows" oor:type="xs:boolean" 
oor:nillable="false">
+          <!-- UIHints: Data - Duplicate Records... -->
+          <info>
+            <desc>Indicates whether to remove rows, or columns in the 'handle 
duplicate records' dialog.</desc>
+            <label>Data includes row/column headers</label>
+          </info>
+          <value>false</value>
+        </prop>
+        <prop oor:name="RemoveRecords" oor:type="xs:boolean" 
oor:nillable="false">
+          <!-- UIHints: Data - Duplicate Records... -->
+          <info>
+            <desc>Indicates whether to select or remove records in the 'handle 
duplicate records' dialog.</desc>
+            <label>Select or remove</label>
+          </info>
+          <value>true</value>
+        </prop>
+      </group>
       <group oor:name="DefaultObjectSize">
         <info>
           <desc>Defines the default size of newly created objects using 
CTRL-Return or CTRL-Click at an object creating Button.</desc>
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 71103f726be8..824b02714f4d 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -499,6 +499,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
     sc/source/ui/miscdlgs/onlyactivesheetsaveddlg \
     sc/source/ui/miscdlgs/optsolver \
     sc/source/ui/miscdlgs/protectiondlg \
+    sc/source/ui/miscdlgs/duplicaterecordsdlg \
     sc/source/ui/miscdlgs/redcom \
     sc/source/ui/miscdlgs/retypepassdlg \
     sc/source/ui/miscdlgs/sharedocdlg \
diff --git a/sc/UIConfig_scalc.mk b/sc/UIConfig_scalc.mk
index a030ef783d73..2be15a1a6618 100644
--- a/sc/UIConfig_scalc.mk
+++ b/sc/UIConfig_scalc.mk
@@ -95,6 +95,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/scalc,\
        sc/uiconfig/scalc/ui/autoformattable \
        sc/uiconfig/scalc/ui/autosum \
        sc/uiconfig/scalc/ui/cellprotectionpage \
+       sc/uiconfig/scalc/ui/duplicaterecordsdlg \
        sc/uiconfig/scalc/ui/changesourcedialog \
        sc/uiconfig/scalc/ui/chardialog \
        sc/uiconfig/scalc/ui/checkwarningdialog \
diff --git a/sc/inc/sc.hrc b/sc/inc/sc.hrc
index ba9054a5a1f8..a1a8be63f46a 100644
--- a/sc/inc/sc.hrc
+++ b/sc/inc/sc.hrc
@@ -277,6 +277,7 @@ class SvxZoomSliderItem;
 
 #define FID_TOGGLEINPUTLINE     TypedWhichId<SfxBoolItem>(VIEW_MENU_START + 1)
 #define FID_TOGGLEHEADERS       (VIEW_MENU_START + 2)
+#define FID_HANDLEDUPLICATERECORDS (VIEW_MENU_START + 3)
 #define FID_SCALE               TypedWhichId<SvxZoomItem>(VIEW_MENU_START + 4)
 #define FID_TOGGLESYNTAX        (VIEW_MENU_START + 5)
 #define FID_TOGGLECOLROWHIGHLIGHTING (VIEW_MENU_START + 6)
diff --git a/sc/inc/strings.hrc b/sc/inc/strings.hrc
index 2277de7826d8..3e23a800974e 100644
--- a/sc/inc/strings.hrc
+++ b/sc/inc/strings.hrc
@@ -437,6 +437,10 @@
 #define STR_CONDITION_THISYEAR                     
NC_("STR_CONDITION_THISYEAR", "date is in this year")
 #define STR_CONDITION_LASTYEAR                     
NC_("STR_CONDITION_LASTYEAR", "date is in last year")
 #define STR_CONDITION_NEXTYEAR                     
NC_("STR_CONDITION_NEXTYEAR", "date is in next year")
+#define STR_DUPLICATERECORDSDLG_WARNING                
NC_("STR_DUPLICATERECORDS_WARNING", "Warning!")
+#define STR_DUPLICATERECORDSDLG_NODATAFOUND            
NC_("STR_DUPLICATERECORDS_NODATAFOUND", "No data found to operate on.")
+#define STR_DUPLICATERECORDS_DATACONATINSROWHEADERS    
NC_("STR_DUPLICATERECORDS_DATACONATINSROWHEADERS", "Data contains row headers")
+#define STR_DUPLICATERECORDS_DATACONATINSCOLUMNHEADERS 
NC_("STR_DUPLICATERECORDS_DATACONATINSCOLUMNHEADERS", "Data contains column 
headers")
 
 
 #define STR_CONTENT_WITH_UNKNOWN_ENCRYPTION 
NC_("STR_CONTENT_WITH_UNKNOWN_ENCRYPTION", "Document contains DRM content that 
is encrypted with an unknown encryption method. Only the un-encrypted content 
will be shown.")
diff --git a/sc/sdi/scalc.sdi b/sc/sdi/scalc.sdi
index d532de343600..d43d4ceea390 100644
--- a/sc/sdi/scalc.sdi
+++ b/sc/sdi/scalc.sdi
@@ -6054,6 +6054,32 @@ SfxBoolItem ViewValueHighlighting FID_TOGGLESYNTAX
     GroupId = SfxGroupId::View;
 ]
 
+SfxBoolItem HandleDuplicateRecords FID_HANDLEDUPLICATERECORDS
+(
+    SfxBoolItem Remove FID_HANDLEDUPLICATERECORDS,
+    SfxBoolItem IncludesHeaders FN_PARAM_1,
+    SfxBoolItem DuplicateRows FN_PARAM_2,
+    SfxInt32Item StartColumn FN_PARAM_3,
+    SfxInt32Item StartRow FN_PARAM_4,
+    SfxInt32Item EndColumn FN_PARAM_5,
+    SfxInt32Item EndRow FN_PARAM_6,
+    SfxInt32Item TabNo FN_PARAM_7
+)
+[
+    AutoUpdate = FALSE,
+    FastCall = FALSE,
+    ReadOnlyDoc = TRUE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    ToolBoxConfig = TRUE,
+    GroupId = SfxGroupId::View;
+]
 SfxBoolItem ViewColumnRowHighlighting FID_TOGGLECOLROWHIGHLIGHTING
 
 [
diff --git a/sc/sdi/tabvwsh.sdi b/sc/sdi/tabvwsh.sdi
index 7130ff4cabd8..48afa923e6fc 100644
--- a/sc/sdi/tabvwsh.sdi
+++ b/sc/sdi/tabvwsh.sdi
@@ -174,6 +174,7 @@ interface TableEditView
 
     FID_SCALESTATUS     [ ExecMethod = Execute; StateMethod = GetState; ]
     FID_TOGGLESYNTAX    [ ExecMethod = Execute; StateMethod = GetState; ]
+    FID_HANDLEDUPLICATERECORDS [ ExecMethod = Execute; StateMethod = GetState; 
]
     FID_TOGGLECOLROWHIGHLIGHTING [ ExecMethod = Execute; StateMethod = 
GetState; ]
     FID_TOGGLEHEADERS   [ ExecMethod = Execute; StateMethod = GetState; ]
     FID_TOGGLEFORMULA   [ ExecMethod = Execute; StateMethod = GetState; ]
diff --git a/sc/source/ui/inc/duplicaterecordsdlg.hxx 
b/sc/source/ui/inc/duplicaterecordsdlg.hxx
new file mode 100644
index 000000000000..29bcd22e8e2f
--- /dev/null
+++ b/sc/source/ui/inc/duplicaterecordsdlg.hxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "viewdata.hxx"
+#include <vcl/weld.hxx>
+
+using namespace css;
+
+struct DuplicatesResponse
+{
+    std::vector<int> vEntries;
+    bool bRemove; // false ==> Select
+    bool bIncludesHeaders;
+    bool bDuplicatRows; // false ==> DuplicateColumns
+};
+
+class ScDuplicateRecordsDlg : public weld::GenericDialogController
+{
+public:
+    ScDuplicateRecordsDlg() = delete;
+    explicit ScDuplicateRecordsDlg(weld::Window* pParent,
+                                   
css::uno::Sequence<uno::Sequence<uno::Any>>& rData,
+                                   ScViewData& rViewData, ScRange& aRange);
+    virtual ~ScDuplicateRecordsDlg() override;
+
+    DuplicatesResponse GetDialogData() { return maResponse; };
+
+private:
+    void Init();
+    void Okay();
+    void SetDialogData(bool bToggle);
+    std::unique_ptr<weld::CheckButton> m_xIncludesHeaders;
+    std::unique_ptr<weld::RadioButton> m_xRadioRow;
+    std::unique_ptr<weld::RadioButton> m_xRadioColumn;
+    std::unique_ptr<weld::RadioButton> m_xRadioSelect;
+    std::unique_ptr<weld::RadioButton> m_xRadioRemove;
+    std::unique_ptr<weld::TreeView> m_xCheckList;
+    std::unique_ptr<weld::CheckButton> m_xAllChkBtn;
+
+    std::unique_ptr<weld::Button> m_xOkBtn;
+    std::unique_ptr<weld::Button> m_xHelpBtn;
+
+    uno::Sequence<uno::Sequence<uno::Any>>& mrCellData;
+    ScRange& mrRange;
+    ScViewData& mrViewData;
+    DuplicatesResponse maResponse;
+
+    void InsertEntry(const OUString& rTxt, bool bToggle);
+
+    DECL_LINK(OrientationHdl, weld::Toggleable&, void);
+    DECL_LINK(HeaderCkbHdl, weld::Toggleable&, void);
+    DECL_LINK(OkHdl, weld::Button&, void);
+    DECL_LINK(AllCheckBtnHdl, weld::Toggleable&, void);
+    DECL_LINK(RecordsChkHdl, const weld::TreeView::iter_col&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx
index 739e98c33537..43ca32993d80 100644
--- a/sc/source/ui/inc/tabvwsh.hxx
+++ b/sc/source/ui/inc/tabvwsh.hxx
@@ -31,6 +31,7 @@
 #include <shellids.hxx>
 #include <tabprotection.hxx>
 #include <com/sun/star/ui/dialogs/DialogClosedEvent.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
 #include <dragdata.hxx>
 
 #include <memory>
@@ -267,6 +268,13 @@ public:
     SC_DLLPUBLIC bool IsRefInputMode() const;
     void            ExecuteInputDirect();
 
+    void HandleDuplicateRecords(css::uno::Reference<css::sheet::XSpreadsheet> 
ActiveSheet,
+                                const css::table::CellRangeAddress& aRange, 
bool bRemove,
+                                bool bIncludesHeaders, bool bDuplicateRows,
+                                const std::vector<int>& rSelectedEntries);
+    css::uno::Reference<css::sheet::XSpreadsheet> 
GetRangeWithSheet(css::table::CellRangeAddress& rRangeData, bool& bHasData, 
bool bHasUnoArguments);
+    void            ExtendSingleSelection(css::table::CellRangeAddress& 
rRangeData);
+
     const ScInputHandler* GetInputHandler() const { return 
mpInputHandler.get(); }
     ScInputHandler* GetInputHandler() { return mpInputHandler.get(); }
     SC_DLLPUBLIC const OUString* GetEditString() const;
diff --git a/sc/source/ui/miscdlgs/duplicaterecordsdlg.cxx 
b/sc/source/ui/miscdlgs/duplicaterecordsdlg.cxx
new file mode 100644
index 000000000000..3dd0eebc6ad5
--- /dev/null
+++ b/sc/source/ui/miscdlgs/duplicaterecordsdlg.cxx
@@ -0,0 +1,214 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scresid.hxx>
+#include <dbdata.hxx>
+#include <cellvalue.hxx>
+#include <duplicaterecordsdlg.hxx>
+#include <string>
+#include <strings.hrc>
+#include <tabprotection.hxx>
+#include <gridwin.hxx>
+#include <vector>
+#include <officecfg/Office/Calc.hxx>
+
+ScDuplicateRecordsDlg::ScDuplicateRecordsDlg(weld::Window* pParent,
+                                             
css::uno::Sequence<uno::Sequence<uno::Any>>& rData,
+                                             ScViewData& rViewData, ScRange& 
rRange)
+    : weld::GenericDialogController(pParent, 
"modules/scalc/ui/duplicaterecordsdlg.ui",
+                                    "DuplicateRecordsDialog")
+    , m_xIncludesHeaders(m_xBuilder->weld_check_button("includesheaders"))
+    , m_xRadioRow(m_xBuilder->weld_radio_button("row"))
+    , m_xRadioColumn(m_xBuilder->weld_radio_button("column"))
+    , m_xRadioSelect(m_xBuilder->weld_radio_button("select"))
+    , m_xRadioRemove(m_xBuilder->weld_radio_button("remove"))
+    , m_xCheckList(m_xBuilder->weld_tree_view("checklist"))
+    , m_xAllChkBtn(m_xBuilder->weld_check_button("allcheckbtn"))
+    , m_xOkBtn(m_xBuilder->weld_button("okaybtn"))
+    , m_xHelpBtn(m_xBuilder->weld_button("helpbutton"))
+    , mrCellData(rData)
+    , mrRange(rRange)
+    , mrViewData(rViewData)
+{
+    m_xCheckList->enable_toggle_buttons(weld::ColumnToggleType::Check);
+    m_xCheckList->connect_toggled(LINK(this, ScDuplicateRecordsDlg, 
RecordsChkHdl));
+    Init();
+}
+
+ScDuplicateRecordsDlg::~ScDuplicateRecordsDlg()
+{
+    auto pChange(comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Calc::Misc::HandleDuplicateRecords::RemoveDuplicateRows::set(
+        m_xRadioRow->get_active(), pChange);
+    pChange->commit();
+
+    
officecfg::Office::Calc::Misc::HandleDuplicateRecords::DataIncludesHeaders::set(
+        m_xIncludesHeaders->get_active(), pChange);
+    pChange->commit();
+
+    officecfg::Office::Calc::Misc::HandleDuplicateRecords::RemoveRecords::set(
+        m_xRadioRemove->get_active(), pChange);
+    pChange->commit();
+}
+
+void ScDuplicateRecordsDlg::SetDialogData(bool bToggle)
+{
+    m_xCheckList->freeze();
+    m_xCheckList->clear();
+
+    if (m_xRadioRow->get_active())
+    {
+        if (m_xIncludesHeaders->get_active())
+        {
+            // insert the first row's contents
+            ScRefCellValue aCell;
+            for (SCCOL i = mrRange.aStart.Col(); i <= mrRange.aEnd.Col(); ++i)
+            {
+                aCell.assign(mrViewData.GetDocument(),
+                             ScAddress{ i, mrRange.aStart.Row(), 
mrRange.aStart.Tab() });
+                InsertEntry(aCell.getString(&mrViewData.GetDocument()), 
bToggle);
+            }
+        }
+        else
+        {
+            for (int i = mrRange.aStart.Col(); i <= mrRange.aEnd.Col(); ++i)
+            {
+                OUString aStr(ScAddress(i, 0, mrViewData.GetTabNo())
+                                  .Format(ScRefFlags::COL_VALID, 
&mrViewData.GetDocument()));
+                InsertEntry(aStr, bToggle);
+            }
+        }
+    }
+    else
+    {
+        // insert row names
+        if (m_xIncludesHeaders->get_active())
+        {
+            ScRefCellValue aCell;
+            for (SCROW i = mrRange.aStart.Row(); i <= mrRange.aEnd.Row(); ++i)
+            {
+                aCell.assign(mrViewData.GetDocument(),
+                             ScAddress{ mrRange.aStart.Col(), i, 
mrRange.aStart.Tab() });
+                InsertEntry(aCell.getString(&mrViewData.GetDocument()), 
bToggle);
+            }
+        }
+        else
+        {
+            for (int i = mrRange.aStart.Row() + 1; i <= mrRange.aEnd.Row() + 
1; ++i)
+            {
+                std::string aStr = std::to_string(i);
+                InsertEntry(rtl::OUString::fromUtf8(aStr), bToggle);
+            }
+        }
+    }
+    m_xCheckList->thaw();
+}
+
+void ScDuplicateRecordsDlg::InsertEntry(const OUString& rTxt, bool bToggle)
+{
+    m_xCheckList->append();
+    const int nRow = m_xCheckList->n_children() - 1;
+    m_xCheckList->set_toggle(nRow, bToggle ? TRISTATE_TRUE : TRISTATE_FALSE);
+    m_xCheckList->set_text(nRow, rTxt, 0);
+    m_xCheckList->set_sensitive(m_xAllChkBtn->get_state() != TRISTATE_TRUE);
+}
+
+void ScDuplicateRecordsDlg::Init()
+{
+    m_xIncludesHeaders->connect_toggled(LINK(this, ScDuplicateRecordsDlg, 
HeaderCkbHdl));
+    m_xRadioRow->connect_toggled(LINK(this, ScDuplicateRecordsDlg, 
OrientationHdl));
+    // m_xRadioColumn->connect_toggled(LINK(this, ScDuplicateRecordsDlg, 
OrientationHdl));
+    m_xOkBtn->connect_clicked(LINK(this, ScDuplicateRecordsDlg, OkHdl));
+    m_xAllChkBtn->connect_toggled(LINK(this, ScDuplicateRecordsDlg, 
AllCheckBtnHdl));
+
+    // defaults (find duplicate rows | data doesn't include headers)
+    m_xRadioRow->set_active(
+        
officecfg::Office::Calc::Misc::HandleDuplicateRecords::RemoveDuplicateRows::get());
+    m_xRadioColumn->set_active(
+        
!officecfg::Office::Calc::Misc::HandleDuplicateRecords::RemoveDuplicateRows::get());
+    m_xIncludesHeaders->set_active(
+        
officecfg::Office::Calc::Misc::HandleDuplicateRecords::DataIncludesHeaders::get());
+    m_xRadioRemove->set_active(
+        
officecfg::Office::Calc::Misc::HandleDuplicateRecords::RemoveRecords::get());
+    m_xRadioSelect->set_active(
+        
!officecfg::Office::Calc::Misc::HandleDuplicateRecords::RemoveRecords::get());
+
+    const OUString aHeaderLabel = m_xRadioRow->get_active()
+                                      ? 
ScResId(STR_DUPLICATERECORDS_DATACONATINSROWHEADERS)
+                                      : 
ScResId(STR_DUPLICATERECORDS_DATACONATINSCOLUMNHEADERS);
+    m_xIncludesHeaders->set_label(aHeaderLabel);
+
+    m_xAllChkBtn->set_state(TRISTATE_FALSE);
+    SetDialogData(true);
+}
+
+IMPL_LINK_NOARG(ScDuplicateRecordsDlg, OrientationHdl, weld::Toggleable&, void)
+{
+    const OUString aHeaderLabel = m_xRadioRow->get_active()
+                                      ? 
ScResId(STR_DUPLICATERECORDS_DATACONATINSROWHEADERS)
+                                      : 
ScResId(STR_DUPLICATERECORDS_DATACONATINSCOLUMNHEADERS);
+    m_xIncludesHeaders->set_label(aHeaderLabel);
+    SetDialogData(true);
+}
+
+IMPL_LINK_NOARG(ScDuplicateRecordsDlg, HeaderCkbHdl, weld::Toggleable&, void)
+{
+    SetDialogData(true);
+}
+
+IMPL_LINK_NOARG(ScDuplicateRecordsDlg, RecordsChkHdl, const 
weld::TreeView::iter_col&, void)
+{
+    int nRet = 0;
+    int nTotalCount = 0;
+
+    m_xCheckList->all_foreach([this, &nRet, &nTotalCount](weld::TreeIter& 
rEntry) {
+        ++nTotalCount;
+        if (m_xCheckList->get_toggle(rEntry) == TRISTATE_TRUE)
+            ++nRet;
+        return false;
+    });
+
+    if (nRet == nTotalCount)
+        m_xAllChkBtn->set_state(TRISTATE_TRUE);
+    else
+        m_xAllChkBtn->set_state(TRISTATE_FALSE);
+}
+
+IMPL_LINK_NOARG(ScDuplicateRecordsDlg, AllCheckBtnHdl, weld::Toggleable&, void)
+{
+    SetDialogData(true);
+}
+
+IMPL_LINK_NOARG(ScDuplicateRecordsDlg, OkHdl, weld::Button&, void)
+{
+    maResponse.bRemove = m_xRadioRemove->get_active();
+    maResponse.bDuplicatRows = m_xRadioRow->get_active();
+    maResponse.bIncludesHeaders = m_xIncludesHeaders->get_active();
+    int nCount = (maResponse.bDuplicatRows ? mrCellData[0].size() : 
mrCellData.size());
+
+    for (int i = 0; i < nCount; ++i)
+    {
+        if (m_xCheckList->get_toggle(i))
+            maResponse.vEntries.push_back(i);
+    }
+
+    m_xDialog->response(RET_OK);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh3.cxx b/sc/source/ui/view/tabvwsh3.cxx
index 2984cb3c9e19..ddaf0fd31fc6 100644
--- a/sc/source/ui/view/tabvwsh3.cxx
+++ b/sc/source/ui/view/tabvwsh3.cxx
@@ -45,6 +45,7 @@
 #include <reffact.hxx>
 #include <tabprotection.hxx>
 #include <protectiondlg.hxx>
+#include <duplicaterecordsdlg.hxx>
 #include <markdata.hxx>
 
 #include <svl/ilstitem.hxx>
@@ -54,6 +55,8 @@
 #include <svx/svxdlg.hxx>
 #include <comphelper/lok.hxx>
 #include <comphelper/string.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/sheet/XCellRangeData.hpp>
 #include <sfx2/lokhelper.hxx>
 #include <scabstdlg.hxx>
 #include <officecfg/Office/Calc.hxx>
@@ -809,6 +812,115 @@ void ScTabViewShell::Execute( SfxRequest& rReq )
                 rReq.Done();
             }
             break;
+        case FID_HANDLEDUPLICATERECORDS:
+            {
+                using namespace com::sun::star;
+                table::CellRangeAddress aCellRange;
+                uno::Reference<sheet::XSpreadsheet> xActiveSheet;
+                DuplicatesResponse aResponse;
+                bool bHasData = true;
+
+                if (pReqArgs)
+                {
+                    const SfxPoolItem* pItem;
+
+                    if (pReqArgs->HasItem(FID_HANDLEDUPLICATERECORDS, &pItem))
+                        aResponse.bRemove = static_cast<const 
SfxBoolItem*>(pItem)->GetValue();
+                    if (pReqArgs->HasItem(FN_PARAM_1, &pItem))
+                        aResponse.bIncludesHeaders = static_cast<const 
SfxBoolItem*>(pItem)->GetValue();
+                    if (pReqArgs->HasItem(FN_PARAM_2, &pItem))
+                        aResponse.bDuplicatRows = static_cast<const 
SfxBoolItem*>(pItem)->GetValue();
+                    if (pReqArgs->HasItem(FN_PARAM_3, &pItem))
+                        aCellRange.StartColumn = static_cast<const 
SfxInt32Item*>(pItem)->GetValue();
+                    if (pReqArgs->HasItem(FN_PARAM_4, &pItem))
+                        aCellRange.StartRow = static_cast<const 
SfxInt32Item*>(pItem)->GetValue();
+                    if (pReqArgs->HasItem(FN_PARAM_5, &pItem))
+                        aCellRange.EndColumn = static_cast<const 
SfxInt32Item*>(pItem)->GetValue();
+                    if (pReqArgs->HasItem(FN_PARAM_6, &pItem))
+                        aCellRange.EndRow = static_cast<const 
SfxInt32Item*>(pItem)->GetValue();
+                    if (pReqArgs->HasItem(FN_PARAM_7, &pItem))
+                        aCellRange.Sheet = static_cast<const 
SfxInt32Item*>(pItem)->GetValue();
+
+                    // check for the tab range here
+                    if (aCellRange.StartColumn < 0 || aCellRange.StartRow < 0
+                        || aCellRange.EndColumn < 0 || aCellRange.EndRow < 0
+                        || aCellRange.StartRow > aCellRange.EndRow
+                        || aCellRange.StartColumn > aCellRange.EndColumn || 
aCellRange.Sheet < 0
+                        || aCellRange.Sheet >= 
GetViewData().GetDocument().GetTableCount())
+                    {
+                        rReq.Done();
+                        break;
+                    }
+                    xActiveSheet = 
GetViewData().GetViewShell()->GetRangeWithSheet(aCellRange,
+                                                                               
    bHasData, true);
+                    if (!bHasData)
+                    {
+                        rReq.Done();
+                        break;
+                    }
+                    int nLenEntries
+                        = (aResponse.bDuplicatRows ? aCellRange.EndColumn - 
aCellRange.StartColumn
+                                                   : aCellRange.EndRow - 
aCellRange.StartRow);
+                    for (int i = 0; i <= nLenEntries; ++i)
+                        aResponse.vEntries.push_back(i);
+                }
+                else
+                {
+                    xActiveSheet = 
GetViewData().GetViewShell()->GetRangeWithSheet(aCellRange,
+                                                                               
    bHasData, false);
+                    if (bHasData)
+                    {
+                        if (!GetViewData().GetMarkData().IsMarked())
+                            
GetViewData().GetViewShell()->ExtendSingleSelection(aCellRange);
+
+                        uno::Reference<frame::XModel> 
xModel(GetViewData().GetDocShell()->GetModel());
+                        uno::Reference<sheet::XSheetCellRange> xSheetRange(
+                                xActiveSheet->getCellRangeByPosition(
+                                    aCellRange.StartColumn, 
aCellRange.StartRow, aCellRange.EndColumn,
+                                    aCellRange.EndRow),
+                                uno::UNO_QUERY);
+
+                        ScRange aRange(ScAddress(aCellRange.StartColumn, 
aCellRange.StartRow,
+                                    GetViewData().GetTabNo()),
+                                ScAddress(aCellRange.EndColumn, 
aCellRange.EndRow,
+                                    GetViewData().GetTabNo()));
+
+                        uno::Reference<sheet::XCellRangeData> 
xCellRangeData(xSheetRange,
+                                uno::UNO_QUERY);
+                        uno::Sequence<uno::Sequence<uno::Any>> aDataArray
+                            = xCellRangeData->getDataArray();
+
+                        ScDuplicateRecordsDlg aDlg(GetFrameWeld(), aDataArray, 
GetViewData(), aRange);
+
+                        bHasData = aDlg.run();
+                        if (bHasData)
+                            aResponse = aDlg.GetDialogData();
+                        else
+                        {
+                            rReq.Done();
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        std::unique_ptr<weld::MessageDialog> aDialog(
+                            Application::CreateMessageDialog(GetFrameWeld(),
+                                                             
VclMessageType::Warning,
+                                                             
VclButtonsType::Ok,
+                                                             
ScResId(STR_DUPLICATERECORDSDLG_NODATAFOUND)));
+                        
aDialog->set_title(ScResId(STR_DUPLICATERECORDSDLG_WARNING));
+                        aDialog->run();
+                    }
+                }
+
+                if (bHasData)
+                    GetViewData().GetViewShell()->HandleDuplicateRecords(
+                            xActiveSheet, aCellRange, aResponse.bRemove, 
aResponse.bIncludesHeaders,
+                            aResponse.bDuplicatRows, aResponse.vEntries);
+
+                rReq.Done();
+            }
+            break;
         case FID_TOGGLECOLROWHIGHLIGHTING:
             {
                 bool bNewVal = 
!officecfg::Office::Calc::Content::Display::ColumnRowHighlighting::get();
diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx
index a61bbf4ae242..60e0b6ab5ad3 100644
--- a/sc/source/ui/view/tabvwsh4.cxx
+++ b/sc/source/ui/view/tabvwsh4.cxx
@@ -80,6 +80,9 @@
 
 #include <com/sun/star/document/XDocumentProperties.hpp>
 #include <com/sun/star/configuration/theDefaultProvider.hpp>
+#include <com/sun/star/sheet/XCellRangeMovement.hpp>
+#include <com/sun/star/sheet/XCellRangeData.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
 #include <comphelper/processfactory.hxx>
 #include <sfx2/lokhelper.hxx>
 #include <comphelper/flagguard.hxx>
@@ -1775,6 +1778,242 @@ 
ScViewOptiChangesListener::ScViewOptiChangesListener(ScTabViewShell& rViewShell)
         m_xColorSchemeChangesNotifier->addChangesListener(this);
 }
 
+static void lcl_RemoveCells(uno::Reference<sheet::XSpreadsheet>& rSheet, 
sal_uInt16 nSheet,
+                     sal_uInt32 nStartColumn, sal_uInt32 nStartRow, sal_uInt32 
nEndColumn,
+                     sal_uInt32 nEndRow, bool bRows)
+{
+    table::CellRangeAddress aCellRange(nSheet, nStartColumn, nStartRow, 
nEndColumn, nEndRow);
+    uno::Reference<sheet::XCellRangeMovement> xCRM(rSheet, uno::UNO_QUERY);
+
+    if (xCRM.is())
+    {
+        if (bRows)
+            xCRM->removeRange(aCellRange, sheet::CellDeleteMode_UP);
+        else
+            xCRM->removeRange(aCellRange, sheet::CellDeleteMode_LEFT);
+    }
+}
+
+/*  For rows (bool bRows), I am passing reference to already existing 
sequence, and comparing the required
+ *  columns, whereas for columns, I am creating a sequence for each, with only 
the checked entries
+ *  in the dialog.
+ */
+static bool lcl_CheckInArray(std::vector<uno::Sequence<uno::Any>>& 
nUniqueRecords,
+                             const uno::Sequence<uno::Any>& nCurrentRecord,
+                             const std::vector<int>& rSelectedEntries, bool 
bRows)
+{
+    for (size_t m = 0; m < nUniqueRecords.size(); ++m)
+    {
+        bool bIsDuplicate = true;
+        for (size_t n = 0; n < rSelectedEntries.size(); ++n)
+        {
+            // when the first different element is found
+            int nColumn = (bRows ? rSelectedEntries[n] : n);
+            if (nUniqueRecords[m][nColumn] != (bRows ? 
nCurrentRecord[rSelectedEntries[n]] : nCurrentRecord[n]))
+            {
+                bIsDuplicate = false;
+                break;
+            }
+        }
+
+        if (bIsDuplicate)
+            return true;
+    }
+    return false;
+}
+
+uno::Reference<css::sheet::XSpreadsheet> 
ScTabViewShell::GetRangeWithSheet(css::table::CellRangeAddress& rRangeData, 
bool& bHasData, bool bHasUnoArguments)
+{
+    // get spreadsheet document model & controller
+    uno::Reference<frame::XModel> 
xModel(GetViewData().GetDocShell()->GetModel());
+    uno::Reference<frame::XController> 
xController(xModel->getCurrentController());
+
+    // spreadsheet's extension of com.sun.star.frame.Controller service
+    uno::Reference<sheet::XSpreadsheetView> SpreadsheetDocument(xController, 
uno::UNO_QUERY);
+    uno::Reference<sheet::XSpreadsheet> ActiveSheet = 
SpreadsheetDocument->getActiveSheet();
+
+    if (!bHasUnoArguments)
+    {
+        // get the selection supplier, extract selection in XSheetCellRange
+        uno::Reference<view::XSelectionSupplier> 
xSelectionSupplier(SpreadsheetDocument, uno::UNO_QUERY);
+        uno::Any Selection = xSelectionSupplier->getSelection();
+        uno::Reference<sheet::XSheetCellRange> SelectedCellRange;
+        Selection >>= SelectedCellRange;
+
+        // Get the Selected Range Address.
+        uno::Reference<sheet::XCellRangeAddressable> xAddressable( 
SelectedCellRange, uno::UNO_QUERY);
+        if (xAddressable.is())
+            rRangeData = xAddressable->getRangeAddress();
+        else
+        {
+            bHasData = false;
+            return ActiveSheet;
+        }
+    }
+
+    SCCOL nStartColumn = rRangeData.StartColumn;
+    SCCOL nEndColumn = rRangeData.EndColumn;
+    SCROW nStartRow = rRangeData.StartRow;
+    SCROW nEndRow = rRangeData.EndRow;
+
+    // shrink to inersection of data and selection. If no intersection ==> 
return
+    bHasData = GetViewData().GetDocument().ShrinkToDataArea(rRangeData.Sheet, 
nStartColumn, nStartRow, nEndColumn, nEndRow);
+
+    rRangeData.StartColumn = nStartColumn;
+    rRangeData.StartRow = nStartRow;
+    rRangeData.EndColumn = nEndColumn;
+    rRangeData.EndRow = nEndRow;
+
+    return ActiveSheet;
+}
+
+void ScTabViewShell::ExtendSingleSelection(css::table::CellRangeAddress& 
rRangeData)
+{
+    SCCOL aStartCol(rRangeData.StartColumn);
+    SCCOL aEndCol(rRangeData.EndColumn);
+    SCROW aStartRow(rRangeData.StartRow);
+    SCROW aEndRow(rRangeData.EndRow);
+
+    GetViewData().GetDocument().GetDataArea(rRangeData.Sheet, aStartCol, 
aStartRow, aEndCol,
+                                            aEndRow, true, false);
+    MarkRange(ScRange(ScAddress(aStartCol, aStartRow, rRangeData.Sheet),
+                      ScAddress(aEndCol, aEndRow, rRangeData.Sheet)));
+
+    rRangeData.StartRow = aStartRow;
+    rRangeData.StartColumn = aStartCol;
+    rRangeData.EndRow = aEndRow;
+    rRangeData.EndColumn = aEndCol;
+}
+
+/* bool bRemove == false ==> highlight duplicate rows */
+void 
ScTabViewShell::HandleDuplicateRecords(css::uno::Reference<css::sheet::XSpreadsheet>
 ActiveSheet,
+                                const css::table::CellRangeAddress& aRange, 
bool bRemove,
+                                bool bIncludesHeaders, bool bDuplicateRows,
+                                const std::vector<int>& rSelectedEntries)
+{
+    if (rSelectedEntries.size() == 0)
+    {
+        Unmark();
+        return;
+    }
+
+    uno::Reference<frame::XModel> 
xModel(GetViewData().GetDocShell()->GetModel());
+    uno::Reference<sheet::XSheetCellRange> xSheetRange(
+            ActiveSheet->getCellRangeByPosition(aRange.StartColumn, 
aRange.StartRow, aRange.EndColumn, aRange.EndRow),
+            uno::UNO_QUERY);
+
+
+    uno::Reference<sheet::XCellRangeData> xCellRangeData(xSheetRange, 
uno::UNO_QUERY);
+    uno::Sequence<uno::Sequence<uno::Any>> aDataArray = 
xCellRangeData->getDataArray();
+
+    uno::Reference< document::XUndoManagerSupplier > xUndoManager( xModel, 
uno::UNO_QUERY );
+    uno::Reference<document::XActionLockable> xLockable(xModel, 
uno::UNO_QUERY);
+
+    uno::Reference<sheet::XCalculatable> xCalculatable(xModel, uno::UNO_QUERY);
+    bool bAutoCalc = xCalculatable->isAutomaticCalculationEnabled();
+
+    comphelper::ScopeGuard aUndoContextGaurd(
+        [&xUndoManager, &xLockable, &xModel, &xCalculatable, &bAutoCalc, 
&bRemove] {
+        xUndoManager->getUndoManager()->leaveUndoContext();
+        if (bRemove)
+            xCalculatable->enableAutomaticCalculation(bAutoCalc);
+        xLockable->removeActionLock();
+        if (xModel->hasControllersLocked())
+            xModel->unlockControllers();
+    });
+
+    xModel->lockControllers();
+    xLockable->addActionLock();
+    if (bRemove)
+        xCalculatable->enableAutomaticCalculation(true);
+    xUndoManager->getUndoManager()->enterUndoContext("HandleDuplicateRecords");
+
+    bool nModifier = false;         // modifier key pressed?
+    bool bNoDuplicatesForSelection = true;
+
+    if (bDuplicateRows)
+    {
+        std::vector<uno::Sequence<uno::Any>> aUnionArray;
+        sal_uInt32 nRow = bIncludesHeaders ? 1 : 0;
+        sal_uInt32 lRows = aDataArray.getLength();
+        sal_uInt32 nDeleteCount = 0;
+
+        while (nRow < lRows)
+        {
+            if (lcl_CheckInArray(aUnionArray, aDataArray[nRow], 
rSelectedEntries, true))
+            {
+                if (bRemove)
+                {
+                    lcl_RemoveCells(ActiveSheet, aRange.Sheet, 
aRange.StartColumn,
+                                    aRange.StartRow + nRow - nDeleteCount, 
aRange.EndColumn,
+                                    aRange.StartRow + nRow - nDeleteCount, 
true);
+                    ++nDeleteCount;
+                }
+                else
+                {
+                    for (int nCol = aRange.StartColumn; nCol <= 
aRange.EndColumn; ++nCol)
+                    {
+                        bNoDuplicatesForSelection = false;
+                        DoneBlockMode( nModifier );
+                        nModifier = true;
+                        InitBlockMode( nCol, aRange.StartRow + nRow, 
aRange.Sheet, false, false);
+                    }
+                }
+            }
+            else
+            {
+                aUnionArray.push_back(aDataArray[nRow]);
+            }
+            ++nRow;
+        }
+    }
+    else
+    {
+        std::vector<uno::Sequence<uno::Any>> aUnionArray;
+        sal_uInt32 nDeleteCount = 0;
+        sal_uInt32 nColumn = bIncludesHeaders ? 1 : 0;
+        sal_uInt32 lColumns = aDataArray[0].getLength();
+
+        while (nColumn < lColumns)
+        {
+            uno::Sequence<uno::Any> aSeq;
+            aSeq.realloc(rSelectedEntries.size());
+            for (size_t i = 0; i < rSelectedEntries.size(); ++i)
+                aSeq.getArray()[i] = aDataArray[rSelectedEntries[i]][nColumn];
+
+            if (lcl_CheckInArray(aUnionArray, aSeq, rSelectedEntries, false))
+            {
+                if (bRemove)
+                {
+                    lcl_RemoveCells(ActiveSheet, aRange.Sheet,
+                                    aRange.StartColumn + nColumn - 
nDeleteCount, aRange.StartRow,
+                                    aRange.StartColumn + nColumn - 
nDeleteCount, aRange.EndRow, false);
+                    ++nDeleteCount;
+                }
+                else
+                {
+                    for (int nRow = aRange.StartRow; nRow <= aRange.EndRow; 
++nRow)
+                    {
+                        bNoDuplicatesForSelection = false;
+                        DoneBlockMode( nModifier );
+                        nModifier = true;
+                        InitBlockMode( aRange.StartColumn + nColumn, nRow, 
aRange.Sheet, false, false);
+                    }
+                }
+            }
+            else
+            {
+                aUnionArray.push_back(aSeq);
+            }
+            ++nColumn;
+        }
+
+    }
+
+    if (bNoDuplicatesForSelection && !bRemove)
+        Unmark();
+}
+
 ScTabViewShell::ScTabViewShell( SfxViewFrame& rViewFrame,
                                 SfxViewShell* pOldSh ) :
     SfxViewShell(rViewFrame, SfxViewShellFlags::HAS_PRINTOPTIONS),
diff --git a/sc/uiconfig/scalc/menubar/menubar.xml 
b/sc/uiconfig/scalc/menubar/menubar.xml
index dad1d6844f4e..61ea6c74b286 100644
--- a/sc/uiconfig/scalc/menubar/menubar.xml
+++ b/sc/uiconfig/scalc/menubar/menubar.xml
@@ -604,6 +604,7 @@
           <menu:menuitem menu:id=".uno:DataFilterHideAutoFilter"/>
         </menu:menupopup>
       </menu:menu>
+      <menu:menuitem menu:id=".uno:HandleDuplicateRecords"/>
       <menu:menuseparator/>
       <menu:menuitem menu:id=".uno:DefineDBName"/>
       <menu:menuitem menu:id=".uno:SelectDB"/>
diff --git a/sc/uiconfig/scalc/ui/duplicaterecordsdlg.ui 
b/sc/uiconfig/scalc/ui/duplicaterecordsdlg.ui
new file mode 100644
index 000000000000..4b21b26d5cb1
--- /dev/null
+++ b/sc/uiconfig/scalc/ui/duplicaterecordsdlg.ui
@@ -0,0 +1,339 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0 -->
+<interface domain="sc">
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkTreeStore" id="liststore1">
+    <columns>
+      <!-- column-name check1 -->
+      <column type="gboolean"/>
+      <!-- column-name text -->
+      <column type="gchararray"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
+      <!-- column-name checkvis1 -->
+      <column type="gboolean"/>
+      <!-- column-name checktri1 -->
+      <column type="gboolean"/>
+    </columns>
+  </object>
+  <object class="GtkDialog" id="DuplicateRecordsDialog">
+    <property name="can-focus">False</property>
+    <property name="border-width">6</property>
+    <property name="title" translatable="yes" 
context="duplicaterecordsdialog|duplicaterecordsdialog">Handle Duplicate 
Records</property>
+    <property name="resizable">False</property>
+    <property name="type-hint">dialog</property>
+    <child internal-child="vbox">
+      <object class="GtkBox">
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">6</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox">
+            <property name="can-focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="layout-style">end</property>
+            <child>
+              <object class="GtkButton" id="helpbutton">
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|helpbutton">_Help</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">True</property>
+                <property name="use-underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+                <property name="secondary">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="okaybtn">
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|okaybtn">_Okay</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">True</property>
+                <property name="use-underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="cancelbtn">
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|cancelbtn">Ca_ncel</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">True</property>
+                <property name="use-underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <!-- n-columns=2 n-rows=5 -->
+          <object class="GtkGrid" id="grid1">
+            <property name="visible">True</property>
+            <property name="can-focus">False</property>
+            <property name="row-spacing">6</property>
+            <property name="column-spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="orientation">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="valign">start</property>
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|orientation">Orientation:</property>
+                <property name="mnemonic-widget">row</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="header">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="halign">start</property>
+                <property name="valign">start</property>
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|header">Hea_der:</property>
+                <property name="use-underline">True</property>
+                <property name="mnemonic-widget">includesheaders</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="action">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="halign">start</property>
+                <property name="valign">start</property>
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|action">Action:</property>
+                <property name="mnemonic-widget">select</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow">
+                <property name="width-request">280</property>
+                <property name="height-request">140</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="margin-top">2</property>
+                <property name="hscrollbar-policy">never</property>
+                <property name="shadow-type">in</property>
+                <child>
+                  <object class="GtkTreeView" id="checklist">
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">True</property>
+                    <property name="hexpand">False</property>
+                    <property name="model">liststore1</property>
+                    <property name="headers-visible">False</property>
+                    <property name="headers-clickable">False</property>
+                    <property name="search-column">0</property>
+                    <property name="show-expanders">False</property>
+                    <child internal-child="selection">
+                      <object class="GtkTreeSelection"/>
+                    </child>
+                    <child>
+                      <object class="GtkTreeViewColumn" id="treeviewcolumn4">
+                        <property name="sizing">fixed</property>
+                        <property name="title" translatable="yes" 
context="duplicaterecordsdialog|treeviewcolumn4">All</property>
+                        <property name="clickable">True</property>
+                        <property name="alignment">0.5</property>
+                        <child>
+                          <object class="GtkCellRendererToggle" 
id="cellrenderer5"/>
+                          <attributes>
+                            <attribute name="visible">3</attribute>
+                            <attribute name="active">0</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkTreeViewColumn" id="treeviewcolumn5">
+                        <property name="resizable">True</property>
+                        <property name="spacing">6</property>
+                        <property name="title" translatable="yes" 
context="duplicaterecordsdialog|treeviewcolumn5">Row/Column</property>
+                        <child>
+                          <object class="GtkCellRendererText" 
id="cellrenderer4"/>
+                          <attributes>
+                            <attribute name="text">1</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">3</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box1">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <child>
+                  <object class="GtkRadioButton" id="row">
+                    <property name="label" translatable="yes" 
context="duplicaterecordsdialog|row">By _Row</property>
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">False</property>
+                    <property name="use-underline">True</property>
+                    <property name="active">True</property>
+                    <property name="draw-indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkRadioButton" id="column">
+                    <property name="label" translatable="yes" 
context="duplicaterecordsdialog|column">By _Column</property>
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">False</property>
+                    <property name="use-underline">True</property>
+                    <property name="active">True</property>
+                    <property name="draw-indicator">True</property>
+                    <property name="group">row</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkBox" id="box2">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <child>
+                  <object class="GtkRadioButton" id="select">
+                    <property name="label" translatable="yes" 
context="duplicaterecordsdialog|select">_Select</property>
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">False</property>
+                    <property name="use-underline">True</property>
+                    <property name="active">True</property>
+                    <property name="draw-indicator">True</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkRadioButton" id="remove">
+                    <property name="label" translatable="yes" 
context="duplicaterecordsdialog|remove">R_emove</property>
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="receives-default">False</property>
+                    <property name="use-underline">True</property>
+                    <property name="active">True</property>
+                    <property name="draw-indicator">True</property>
+                    <property name="group">select</property>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">4</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="includesheaders">
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|includesheaders">Data contains row/col 
headers</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">False</property>
+                <property name="use-underline">True</property>
+                <property name="draw-indicator">True</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="items">
+                <property name="visible">True</property>
+                <property name="can-focus">False</property>
+                <property name="halign">start</property>
+                <property name="valign">start</property>
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|items">Items:</property>
+                <property name="mnemonic-widget">allcheckbtn</property>
+              </object>
+              <packing>
+                <property name="left-attach">0</property>
+                <property name="top-attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkCheckButton" id="allcheckbtn">
+                <property name="label" translatable="yes" 
context="duplicaterecordsdialog|allcheckbtn">_All</property>
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="receives-default">False</property>
+                <property name="use-underline">True</property>
+                <property name="draw-indicator">True</property>
+              </object>
+              <packing>
+                <property name="left-attach">1</property>
+                <property name="top-attach">2</property>
+              </packing>
+            </child>
+            <child>
+              <placeholder/>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-11">helpbutton</action-widget>
+      <action-widget response="-5">okaybtn</action-widget>
+      <action-widget response="-6">cancelbtn</action-widget>
+    </action-widgets>
+  </object>
+</interface>

Reply via email to