1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include "breakpoint.hxx"
23 #include "brkdlg.hxx"
24 #include <basobj.hxx>
25 
26 #include <sfx2/dispatch.hxx>
27 #include <sfx2/sfxsids.hrc>
28 
29 namespace basctl
30 {
31 // FIXME  Why does BreakPointDialog allow only sal_uInt16 for break-point line
32 // numbers, whereas BreakPoint supports sal_uLong?
33 
34 namespace
35 {
lcl_ParseText(OUString const & rText,size_t & rLineNr)36 bool lcl_ParseText(OUString const& rText, size_t& rLineNr)
37 {
38     // aText should look like "# n" where
39     // n > 0 && n < std::numeric_limits< sal_uInt16 >::max().
40     // All spaces are ignored, so there can even be spaces within the
41     // number n.  (Maybe it would be better to ignore all whitespace instead
42     // of just spaces.)
43     OUString aText(rText.replaceAll(" ", ""));
44     if (aText.isEmpty())
45         return false;
46     sal_Unicode cFirst = aText[0];
47     if (cFirst != '#' && (cFirst < '0' || cFirst > '9'))
48         return false;
49     if (cFirst == '#')
50         aText = aText.copy(1);
51     // XXX Assumes that sal_uInt16 is contained within sal_Int32:
52     sal_Int32 n = aText.toInt32();
53     if (n <= 0)
54         return false;
55     rLineNr = static_cast<size_t>(n);
56     return true;
57 }
58 
59 } // namespace
60 
BreakPointDialog(weld::Window * pParent,BreakPointList & rBrkPntList)61 BreakPointDialog::BreakPointDialog(weld::Window* pParent, BreakPointList& rBrkPntList)
62     : GenericDialogController(pParent, "modules/BasicIDE/ui/managebreakpoints.ui",
63                               "ManageBreakpointsDialog")
64     , m_rOriginalBreakPointList(rBrkPntList)
65     , m_aModifiedBreakPointList(rBrkPntList)
66     , m_xComboBox(m_xBuilder->weld_entry_tree_view("entriesgrid", "entries", "entrieslist"))
67     , m_xOKButton(m_xBuilder->weld_button("ok"))
68     , m_xNewButton(m_xBuilder->weld_button("new"))
69     , m_xDelButton(m_xBuilder->weld_button("delete"))
70     , m_xCheckBox(m_xBuilder->weld_check_button("active"))
71     , m_xNumericField(m_xBuilder->weld_spin_button("pass"))
72 {
73     m_xComboBox->set_size_request(m_xComboBox->get_approximate_digit_width() * 20, -1);
74     m_xComboBox->set_height_request_by_rows(12);
75 
76     m_xComboBox->freeze();
77     for (size_t i = 0, n = m_aModifiedBreakPointList.size(); i < n; ++i)
78     {
79         BreakPoint& rBrk = m_aModifiedBreakPointList.at(i);
80         OUString aEntryStr("# " + OUString::number(rBrk.nLine));
81         m_xComboBox->append_text(aEntryStr);
82     }
83     m_xComboBox->thaw();
84 
85     m_xOKButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl));
86     m_xNewButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl));
87     m_xDelButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl));
88 
89     m_xCheckBox->connect_toggled(LINK(this, BreakPointDialog, CheckBoxHdl));
90     m_xComboBox->connect_changed(LINK(this, BreakPointDialog, EditModifyHdl));
91     m_xComboBox->connect_row_activated(LINK(this, BreakPointDialog, TreeModifyHdl));
92     m_xComboBox->grab_focus();
93 
94     m_xNumericField->set_range(0, 0x7FFFFFFF);
95     m_xNumericField->set_increments(1, 10);
96     m_xNumericField->connect_value_changed(LINK(this, BreakPointDialog, FieldModifyHdl));
97 
98     if (m_xComboBox->get_count())
99         m_xComboBox->set_active(0);
100 
101     if (m_aModifiedBreakPointList.size())
102         UpdateFields(m_aModifiedBreakPointList.at(0));
103 
104     CheckButtons();
105 }
106 
~BreakPointDialog()107 BreakPointDialog::~BreakPointDialog() {}
108 
SetCurrentBreakPoint(BreakPoint const & rBrk)109 void BreakPointDialog::SetCurrentBreakPoint(BreakPoint const& rBrk)
110 {
111     OUString aStr("# " + OUString::number(rBrk.nLine));
112     m_xComboBox->set_entry_text(aStr);
113     UpdateFields(rBrk);
114 }
115 
CheckButtons()116 void BreakPointDialog::CheckButtons()
117 {
118     // "New" button is enabled if the combo box edit contains a valid line
119     // number that is not already present in the combo box list; otherwise
120     // "OK" and "Delete" buttons are enabled:
121     size_t nLine;
122     if (lcl_ParseText(m_xComboBox->get_active_text(), nLine)
123         && m_aModifiedBreakPointList.FindBreakPoint(nLine) == nullptr)
124     {
125         m_xNewButton->set_sensitive(true);
126         m_xOKButton->set_sensitive(false);
127         m_xDelButton->set_sensitive(false);
128         m_xDelButton->set_has_default(false);
129         m_xNewButton->set_has_default(true);
130     }
131     else
132     {
133         m_xNewButton->set_sensitive(false);
134         m_xOKButton->set_sensitive(true);
135         m_xDelButton->set_sensitive(true);
136         m_xNewButton->set_has_default(false);
137         m_xDelButton->set_has_default(true);
138     }
139 }
140 
IMPL_LINK(BreakPointDialog,CheckBoxHdl,weld::Toggleable &,rButton,void)141 IMPL_LINK(BreakPointDialog, CheckBoxHdl, weld::Toggleable&, rButton, void)
142 {
143     BreakPoint* pBrk = GetSelectedBreakPoint();
144     if (pBrk)
145         pBrk->bEnabled = rButton.get_active();
146 }
147 
IMPL_LINK(BreakPointDialog,EditModifyHdl,weld::ComboBox &,rBox,void)148 IMPL_LINK(BreakPointDialog, EditModifyHdl, weld::ComboBox&, rBox, void)
149 {
150     CheckButtons();
151 
152     int nEntry = rBox.find_text(rBox.get_active_text());
153     if (nEntry == -1)
154         return;
155     BreakPoint& rBrk = m_aModifiedBreakPointList.at(nEntry);
156     UpdateFields(rBrk);
157 }
158 
IMPL_LINK(BreakPointDialog,FieldModifyHdl,weld::SpinButton &,rEdit,void)159 IMPL_LINK(BreakPointDialog, FieldModifyHdl, weld::SpinButton&, rEdit, void)
160 {
161     BreakPoint* pBrk = GetSelectedBreakPoint();
162     if (pBrk)
163         pBrk->nStopAfter = rEdit.get_value();
164 }
165 
IMPL_LINK_NOARG(BreakPointDialog,TreeModifyHdl,weld::TreeView &,bool)166 IMPL_LINK_NOARG(BreakPointDialog, TreeModifyHdl, weld::TreeView&, bool)
167 {
168     if (m_xDelButton->get_sensitive())
169         ButtonHdl(*m_xDelButton);
170     return true;
171 }
172 
IMPL_LINK(BreakPointDialog,ButtonHdl,weld::Button &,rButton,void)173 IMPL_LINK(BreakPointDialog, ButtonHdl, weld::Button&, rButton, void)
174 {
175     if (&rButton == m_xOKButton.get())
176     {
177         m_rOriginalBreakPointList.transfer(m_aModifiedBreakPointList);
178         m_xDialog->response(RET_OK);
179     }
180     else if (&rButton == m_xNewButton.get())
181     {
182         // keep checkbox in mind!
183         OUString aText(m_xComboBox->get_active_text());
184         size_t nLine;
185         bool bValid = lcl_ParseText(aText, nLine);
186         if (bValid)
187         {
188             BreakPoint aBrk(nLine);
189             aBrk.bEnabled = m_xCheckBox->get_active();
190             aBrk.nStopAfter = static_cast<size_t>(m_xNumericField->get_value());
191             m_aModifiedBreakPointList.InsertSorted(aBrk);
192             OUString aEntryStr("# " + OUString::number(aBrk.nLine));
193             m_xComboBox->append_text(aEntryStr);
194             if (SfxDispatcher* pDispatcher = GetDispatcher())
195                 pDispatcher->Execute(SID_BASICIDE_BRKPNTSCHANGED);
196         }
197         else
198         {
199             m_xComboBox->set_active_text(aText);
200             m_xComboBox->grab_focus();
201         }
202         CheckButtons();
203     }
204     else if (&rButton == m_xDelButton.get())
205     {
206         int nEntry = m_xComboBox->find_text(m_xComboBox->get_active_text());
207         if (nEntry != -1)
208         {
209             m_aModifiedBreakPointList.remove(nEntry);
210             m_xComboBox->remove(nEntry);
211             if (nEntry && nEntry >= m_xComboBox->get_count())
212                 nEntry--;
213             m_xComboBox->set_active_text(m_xComboBox->get_text(nEntry));
214             if (SfxDispatcher* pDispatcher = GetDispatcher())
215                 pDispatcher->Execute(SID_BASICIDE_BRKPNTSCHANGED);
216             CheckButtons();
217         }
218     }
219 }
220 
UpdateFields(BreakPoint const & rBrk)221 void BreakPointDialog::UpdateFields(BreakPoint const& rBrk)
222 {
223     m_xCheckBox->set_active(rBrk.bEnabled);
224     m_xNumericField->set_value(rBrk.nStopAfter);
225 }
226 
GetSelectedBreakPoint()227 BreakPoint* BreakPointDialog::GetSelectedBreakPoint()
228 {
229     int nEntry = m_xComboBox->find_text(m_xComboBox->get_active_text());
230     if (nEntry == -1)
231         return nullptr;
232     return &m_aModifiedBreakPointList.at(nEntry);
233 }
234 
235 } // namespace basctl
236 
237 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
238