From 89f0ffd2d9d698e47b2e504927000ee3b1f9c603 Mon Sep 17 00:00:00 2001 From: Rodion Iafarov Date: Wed, 5 Dec 2018 10:54:12 +0100 Subject: [PATCH] Add all sources from libyui --- Makefile.cvs | 23 + src/CMakeLists.txt | 1 + src/FSize.cc | 171 ++++++ src/FSize.h | 224 +++++++ src/ImplPtr.h | 87 +++ src/Notes.h | 43 ++ src/TreeItem.h | 315 ++++++++++ src/YAlignment.cc | 396 ++++++++++++ src/YAlignment.h | 210 +++++++ src/YApplication.cc | 300 +++++++++ src/YApplication.h | 448 ++++++++++++++ src/YBarGraph.cc | 241 ++++++++ src/YBarGraph.h | 325 ++++++++++ src/YBothDim.h | 99 +++ src/YBuiltinCaller.h | 58 ++ src/YBusyIndicator.cc | 160 +++++ src/YBusyIndicator.h | 140 +++++ src/YButtonBox.cc | 650 ++++++++++++++++++++ src/YButtonBox.h | 395 ++++++++++++ src/YCheckBox.cc | 131 ++++ src/YCheckBox.h | 206 +++++++ src/YCheckBoxFrame.cc | 159 +++++ src/YCheckBoxFrame.h | 188 ++++++ src/YChildrenManager.h | 237 +++++++ src/YColor.h | 90 +++ src/YComboBox.cc | 234 +++++++ src/YComboBox.h | 243 ++++++++ src/YCommandLine.cc | 145 +++++ src/YCommandLine.h | 123 ++++ src/YContextMenu.cc | 203 ++++++ src/YContextMenu.h | 188 ++++++ src/YDateField.cc | 62 ++ src/YDateField.h | 69 +++ src/YDialog.cc | 823 +++++++++++++++++++++++++ src/YDialog.h | 418 +++++++++++++ src/YDialogSpy.cc | 899 +++++++++++++++++++++++++++ src/YDialogSpy.h | 102 +++ src/YDownloadProgress.cc | 198 ++++++ src/YDownloadProgress.h | 159 +++++ src/YDumbTab.cc | 150 +++++ src/YDumbTab.h | 157 +++++ src/YEmpty.cc | 59 ++ src/YEmpty.h | 77 +++ src/YEnvVar.cc | 114 ++++ src/YEnvVar.h | 102 +++ src/YEvent.cc | 147 +++++ src/YEvent.h | 365 +++++++++++ src/YEventFilter.cc | 66 ++ src/YEventFilter.h | 120 ++++ src/YExternalWidgetFactory.h | 51 ++ src/YExternalWidgets.cc | 131 ++++ src/YExternalWidgets.h | 104 ++++ src/YFrame.cc | 115 ++++ src/YFrame.h | 111 ++++ src/YGraph.cc | 162 +++++ src/YGraph.h | 166 +++++ src/YGraphPlugin.h | 66 ++ src/YIconLoader.cc | 117 ++++ src/YIconLoader.h | 57 ++ src/YImage.cc | 111 ++++ src/YImage.h | 126 ++++ src/YInputField.cc | 198 ++++++ src/YInputField.h | 215 +++++++ src/YIntField.cc | 193 ++++++ src/YIntField.h | 195 ++++++ src/YItem.cc | 33 + src/YItem.h | 209 +++++++ src/YLabel.cc | 191 ++++++ src/YLabel.h | 176 ++++++ src/YLayoutBox.cc | 778 +++++++++++++++++++++++ src/YLayoutBox.h | 224 +++++++ src/YLogView.cc | 298 +++++++++ src/YLogView.h | 222 +++++++ src/YMacro.cc | 109 ++++ src/YMacro.h | 126 ++++ src/YMacroPlayer.h | 67 ++ src/YMacroRecorder.h | 87 +++ src/YMenuButton.cc | 264 ++++++++ src/YMenuButton.h | 191 ++++++ src/YMenuItem.h | 92 +++ src/YMultiLineEdit.cc | 156 +++++ src/YMultiLineEdit.h | 184 ++++++ src/YMultiProgressMeter.cc | 182 ++++++ src/YMultiProgressMeter.h | 173 ++++++ src/YMultiSelectionBox.cc | 143 +++++ src/YMultiSelectionBox.h | 144 +++++ src/YOptionalWidgetFactory.cc | 282 +++++++++ src/YOptionalWidgetFactory.h | 156 +++++ src/YPackageSelector.cc | 40 ++ src/YPackageSelector.h | 77 +++ src/YPackageSelectorPlugin.h | 66 ++ src/YPartitionSplitter.cc | 202 ++++++ src/YPartitionSplitter.h | 190 ++++++ src/YPath.cc | 179 ++++++ src/YPath.h | 81 +++ src/YPopupInternal.cc | 147 +++++ src/YPopupInternal.h | 47 ++ src/YProgressBar.cc | 154 +++++ src/YProgressBar.h | 126 ++++ src/YProperty.cc | 173 ++++++ src/YProperty.h | 307 +++++++++ src/YPropertyEditor.cc | 296 +++++++++ src/YPropertyEditor.h | 55 ++ src/YPushButton.cc | 274 +++++++++ src/YPushButton.h | 231 +++++++ src/YRadioButton.cc | 205 ++++++ src/YRadioButton.h | 209 +++++++ src/YRadioButtonGroup.cc | 169 +++++ src/YRadioButtonGroup.h | 160 +++++ src/YReplacePoint.cc | 38 ++ src/YReplacePoint.h | 63 ++ src/YRichText.cc | 166 +++++ src/YRichText.h | 168 +++++ src/YRpmGroupsTree.cc | 283 +++++++++ src/YRpmGroupsTree.h | 79 +++ src/YSelectionBox.cc | 153 +++++ src/YSelectionBox.h | 158 +++++ src/YSelectionWidget.cc | 506 +++++++++++++++ src/YSelectionWidget.h | 341 ++++++++++ src/YSettings.cc | 200 ++++++ src/YSettings.h | 139 +++++ src/YShortcut.cc | 352 +++++++++++ src/YShortcut.h | 271 ++++++++ src/YShortcutManager.cc | 410 ++++++++++++ src/YShortcutManager.h | 175 ++++++ src/YSimpleEventHandler.cc | 176 ++++++ src/YSimpleEventHandler.h | 141 +++++ src/YSimpleInputField.cc | 122 ++++ src/YSimpleInputField.h | 137 +++++ src/YSingleChildContainerWidget.cc | 74 +++ src/YSingleChildContainerWidget.h | 81 +++ src/YSlider.cc | 72 +++ src/YSlider.h | 80 +++ src/YSpacing.cc | 109 ++++ src/YSpacing.h | 118 ++++ src/YSquash.cc | 86 +++ src/YSquash.h | 88 +++ src/YStringTree.cc | 216 +++++++ src/YStringTree.h | 193 ++++++ src/YTable.cc | 222 +++++++ src/YTable.h | 214 +++++++ src/YTableHeader.cc | 100 +++ src/YTableHeader.h | 90 +++ src/YTableItem.cc | 181 ++++++ src/YTableItem.h | 325 ++++++++++ src/YTimeField.cc | 62 ++ src/YTimeField.h | 67 ++ src/YTimezoneSelector.cc | 98 +++ src/YTimezoneSelector.h | 110 ++++ src/YTransText.h | 130 ++++ src/YTree.cc | 168 +++++ src/YTree.h | 182 ++++++ src/YTreeItem.cc | 108 ++++ src/YTreeItem.h | 139 +++++ src/YTypes.h | 108 ++++ src/YUI.cc | 523 ++++++++++++++++ src/YUI.h | 376 ++++++++++++ src/YUIException.cc | 209 +++++++ src/YUIException.h | 957 +++++++++++++++++++++++++++++ src/YUILoader.cc | 258 ++++++++ src/YUILoader.h | 164 +++++ src/YUILog.cc | 568 +++++++++++++++++ src/YUILog.h | 240 ++++++++ src/YUIPlugin.cc | 119 ++++ src/YUIPlugin.h | 111 ++++ src/YUISymbols.h | 345 +++++++++++ src/YWidget.cc | 789 ++++++++++++++++++++++++ src/YWidget.h | 720 ++++++++++++++++++++++ src/YWidgetFactory.cc | 272 ++++++++ src/YWidgetFactory.h | 202 ++++++ src/YWidgetID.cc | 86 +++ src/YWidgetID.h | 118 ++++ src/YWidget_OptimizeChanges.h | 58 ++ src/YWizard.cc | 140 +++++ src/YWizard.h | 354 +++++++++++ 175 files changed, 34621 insertions(+) create mode 100644 Makefile.cvs create mode 100644 src/CMakeLists.txt create mode 100644 src/FSize.cc create mode 100644 src/FSize.h create mode 100644 src/ImplPtr.h create mode 100644 src/Notes.h create mode 100644 src/TreeItem.h create mode 100644 src/YAlignment.cc create mode 100644 src/YAlignment.h create mode 100644 src/YApplication.cc create mode 100644 src/YApplication.h create mode 100644 src/YBarGraph.cc create mode 100644 src/YBarGraph.h create mode 100644 src/YBothDim.h create mode 100644 src/YBuiltinCaller.h create mode 100644 src/YBusyIndicator.cc create mode 100644 src/YBusyIndicator.h create mode 100644 src/YButtonBox.cc create mode 100644 src/YButtonBox.h create mode 100644 src/YCheckBox.cc create mode 100644 src/YCheckBox.h create mode 100644 src/YCheckBoxFrame.cc create mode 100644 src/YCheckBoxFrame.h create mode 100644 src/YChildrenManager.h create mode 100644 src/YColor.h create mode 100644 src/YComboBox.cc create mode 100644 src/YComboBox.h create mode 100644 src/YCommandLine.cc create mode 100644 src/YCommandLine.h create mode 100644 src/YContextMenu.cc create mode 100644 src/YContextMenu.h create mode 100644 src/YDateField.cc create mode 100644 src/YDateField.h create mode 100644 src/YDialog.cc create mode 100644 src/YDialog.h create mode 100644 src/YDialogSpy.cc create mode 100644 src/YDialogSpy.h create mode 100644 src/YDownloadProgress.cc create mode 100644 src/YDownloadProgress.h create mode 100644 src/YDumbTab.cc create mode 100644 src/YDumbTab.h create mode 100644 src/YEmpty.cc create mode 100644 src/YEmpty.h create mode 100644 src/YEnvVar.cc create mode 100644 src/YEnvVar.h create mode 100644 src/YEvent.cc create mode 100644 src/YEvent.h create mode 100644 src/YEventFilter.cc create mode 100644 src/YEventFilter.h create mode 100644 src/YExternalWidgetFactory.h create mode 100644 src/YExternalWidgets.cc create mode 100644 src/YExternalWidgets.h create mode 100644 src/YFrame.cc create mode 100644 src/YFrame.h create mode 100644 src/YGraph.cc create mode 100644 src/YGraph.h create mode 100644 src/YGraphPlugin.h create mode 100644 src/YIconLoader.cc create mode 100644 src/YIconLoader.h create mode 100644 src/YImage.cc create mode 100644 src/YImage.h create mode 100644 src/YInputField.cc create mode 100644 src/YInputField.h create mode 100644 src/YIntField.cc create mode 100644 src/YIntField.h create mode 100644 src/YItem.cc create mode 100644 src/YItem.h create mode 100644 src/YLabel.cc create mode 100644 src/YLabel.h create mode 100644 src/YLayoutBox.cc create mode 100644 src/YLayoutBox.h create mode 100644 src/YLogView.cc create mode 100644 src/YLogView.h create mode 100644 src/YMacro.cc create mode 100644 src/YMacro.h create mode 100644 src/YMacroPlayer.h create mode 100644 src/YMacroRecorder.h create mode 100644 src/YMenuButton.cc create mode 100644 src/YMenuButton.h create mode 100644 src/YMenuItem.h create mode 100644 src/YMultiLineEdit.cc create mode 100644 src/YMultiLineEdit.h create mode 100644 src/YMultiProgressMeter.cc create mode 100644 src/YMultiProgressMeter.h create mode 100644 src/YMultiSelectionBox.cc create mode 100644 src/YMultiSelectionBox.h create mode 100644 src/YOptionalWidgetFactory.cc create mode 100644 src/YOptionalWidgetFactory.h create mode 100644 src/YPackageSelector.cc create mode 100644 src/YPackageSelector.h create mode 100644 src/YPackageSelectorPlugin.h create mode 100644 src/YPartitionSplitter.cc create mode 100644 src/YPartitionSplitter.h create mode 100644 src/YPath.cc create mode 100644 src/YPath.h create mode 100644 src/YPopupInternal.cc create mode 100644 src/YPopupInternal.h create mode 100644 src/YProgressBar.cc create mode 100644 src/YProgressBar.h create mode 100644 src/YProperty.cc create mode 100644 src/YProperty.h create mode 100644 src/YPropertyEditor.cc create mode 100644 src/YPropertyEditor.h create mode 100644 src/YPushButton.cc create mode 100644 src/YPushButton.h create mode 100644 src/YRadioButton.cc create mode 100644 src/YRadioButton.h create mode 100644 src/YRadioButtonGroup.cc create mode 100644 src/YRadioButtonGroup.h create mode 100644 src/YReplacePoint.cc create mode 100644 src/YReplacePoint.h create mode 100644 src/YRichText.cc create mode 100644 src/YRichText.h create mode 100644 src/YRpmGroupsTree.cc create mode 100644 src/YRpmGroupsTree.h create mode 100644 src/YSelectionBox.cc create mode 100644 src/YSelectionBox.h create mode 100644 src/YSelectionWidget.cc create mode 100644 src/YSelectionWidget.h create mode 100644 src/YSettings.cc create mode 100644 src/YSettings.h create mode 100644 src/YShortcut.cc create mode 100644 src/YShortcut.h create mode 100644 src/YShortcutManager.cc create mode 100644 src/YShortcutManager.h create mode 100644 src/YSimpleEventHandler.cc create mode 100644 src/YSimpleEventHandler.h create mode 100644 src/YSimpleInputField.cc create mode 100644 src/YSimpleInputField.h create mode 100644 src/YSingleChildContainerWidget.cc create mode 100644 src/YSingleChildContainerWidget.h create mode 100644 src/YSlider.cc create mode 100644 src/YSlider.h create mode 100644 src/YSpacing.cc create mode 100644 src/YSpacing.h create mode 100644 src/YSquash.cc create mode 100644 src/YSquash.h create mode 100644 src/YStringTree.cc create mode 100644 src/YStringTree.h create mode 100644 src/YTable.cc create mode 100644 src/YTable.h create mode 100644 src/YTableHeader.cc create mode 100644 src/YTableHeader.h create mode 100644 src/YTableItem.cc create mode 100644 src/YTableItem.h create mode 100644 src/YTimeField.cc create mode 100644 src/YTimeField.h create mode 100644 src/YTimezoneSelector.cc create mode 100644 src/YTimezoneSelector.h create mode 100644 src/YTransText.h create mode 100644 src/YTree.cc create mode 100644 src/YTree.h create mode 100644 src/YTreeItem.cc create mode 100644 src/YTreeItem.h create mode 100644 src/YTypes.h create mode 100644 src/YUI.cc create mode 100644 src/YUI.h create mode 100644 src/YUIException.cc create mode 100644 src/YUIException.h create mode 100644 src/YUILoader.cc create mode 100644 src/YUILoader.h create mode 100644 src/YUILog.cc create mode 100644 src/YUILog.h create mode 100644 src/YUIPlugin.cc create mode 100644 src/YUIPlugin.h create mode 100644 src/YUISymbols.h create mode 100644 src/YWidget.cc create mode 100644 src/YWidget.h create mode 100644 src/YWidgetFactory.cc create mode 100644 src/YWidgetFactory.h create mode 100644 src/YWidgetID.cc create mode 100644 src/YWidgetID.h create mode 100644 src/YWidget_OptimizeChanges.h create mode 100644 src/YWizard.cc create mode 100644 src/YWizard.h diff --git a/Makefile.cvs b/Makefile.cvs new file mode 100644 index 0000000..3536d20 --- /dev/null +++ b/Makefile.cvs @@ -0,0 +1,23 @@ +# +# Makefile.cvs +# + +all: configure + +configure: clean + ./bootstrap.sh ; \ + mkdir build ; \ + cd build ; \ + cmake -DCMAKE_BUILD_TYPE=RELEASE .. + +install: configure + cd build ; \ + make && make install + +reconf: + cd build ; \ + cmake rebuild_cache + +clean: + rm -rf build \ + CMakeLists.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..926b807 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1 @@ +PROCESS_SOURCES() diff --git a/src/FSize.cc b/src/FSize.cc new file mode 100644 index 0000000..307ae71 --- /dev/null +++ b/src/FSize.cc @@ -0,0 +1,171 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + Copyright (C) 2018 SUSE LLC + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: FSize.cc + + Author: Michael Andres + Maintainer: Michael Andres + + Purpose: + +/-*/ + +#include +#include + +#include "FSize.h" + +// arbitrary precision float for floating point division +#include + +using boost::multiprecision::cpp_int; + +const cpp_int FSize::KB = 1024; +const cpp_int FSize::MB = FSize::KB * 1024; +const cpp_int FSize::GB = FSize::MB * 1024; +const cpp_int FSize::TB = FSize::GB * 1024; +const cpp_int FSize::PB = FSize::TB * 1024; +const cpp_int FSize::EB = FSize::PB * 1024; +const cpp_int FSize::ZB = FSize::EB * 1024; +const cpp_int FSize::YB = FSize::ZB * 1024; + + +FSize::FSize( const std::string &sizeStr, const Unit unit_r ) + : _size( cpp_int(sizeStr) * factor( unit_r ) ) +{ +} + +// +// +// METHOD NAME : FSize::fillBlock +// METHOD TYPE : FSize & +// +// DESCRIPTION : +// +FSize & FSize::fillBlock( FSize blocksize_r ) +{ + if ( _size > 0 && cpp_int(blocksize_r) > 0) { + cpp_int diff = _size % cpp_int(blocksize_r); + if ( diff ) { + if ( _size > 0 ) + _size += cpp_int(blocksize_r); + _size -= diff; + } + } + return *this; +} + +// +// +// METHOD NAME : FSize::bestUnit +// METHOD TYPE : FSize::Unit +// +// DESCRIPTION : +// +FSize::Unit FSize::bestUnit() const +{ + cpp_int usize = abs(_size); + if ( usize < KB ) + return Unit::B; + if ( usize < MB ) + return Unit::K; + if ( usize < GB ) + return Unit::M; + if ( usize < TB ) + return Unit::G; + if ( usize < PB ) + return Unit::T; + if ( usize < EB ) + return Unit::P; + if ( usize < ZB ) + return Unit::E; + if ( usize < YB ) + return Unit::Z; + return Unit::Y; +} + +// +// +// METHOD NAME : FSize::form +// METHOD TYPE : std::string +// +// DESCRIPTION : +// +std::string FSize::form( const Unit unit_r, unsigned fw, unsigned prec, const bool showunit ) const +{ + if ( prec == bestPrec ) { + switch ( unit_r ) + { + case Unit::Y: prec = 3; break; + case Unit::Z: prec = 3; break; + case Unit::E: prec = 3; break; + case Unit::P: prec = 3; break; + case Unit::T: prec = 3; break; + case Unit::G: prec = 2; break; + case Unit::M: prec = 1; break; + case Unit::K: prec = 1; break; + case Unit::B: prec = 0; break; + } +} else if ( unit_r == Unit::B ) + prec = 0; // doesn't make sense for Byte + + std::ostringstream str; + // set the precision and field width, use fixed notation (not the scientific Xe+Y) + str << std::setprecision(prec) << std::setfill(' ') << std::setw(fw) << std::fixed; + + if (prec == 0) + // no decimal part required, we can use integer division, + // add one unit half for correct rounding + str << (_size + (factor( unit_r ) / 2))/ factor( unit_r ); + else + // otherwise convert to boost floats + str << (boost::multiprecision::cpp_bin_float_50)( _size ) / + (boost::multiprecision::cpp_bin_float_50)(factor( unit_r ) ); + + if ( showunit ) + str << " " << unit( unit_r ); + + return str.str(); +} + + +// +// +// METHOD NAME : FSize::asString +// METHOD TYPE : std::string +// +// DESCRIPTION : +// +std::string FSize::asString() const +{ + return form(); +} + +std::ostream& operator<<(std::ostream &ostr, const FSize &fsize) +{ + ostr << fsize.asString(); + return ostr; +} + +std::ostream& operator<<(std::ostream &ostr, const FSize::Unit unit) +{ + ostr << FSize::unit(unit); + return ostr; +} diff --git a/src/FSize.h b/src/FSize.h new file mode 100644 index 0000000..b30a7af --- /dev/null +++ b/src/FSize.h @@ -0,0 +1,224 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + Copyright (C) 2018 SUSE LLC + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: FSize.h + + Author: Michael Andres + Maintainer: Michael Andres + + Purpose: Store and operate on (file/package/partition) sizes. + +/-*/ +#ifndef _FSize_h_ +#define _FSize_h_ + +#include +#include + +// arbitrary precision integer +#include +// generate additional operators via the boost templates +#include + +// +// CLASS NAME : FSize +// +/** + * Store and operate on (file/package/partition) sizes. + **/ +class FSize : + // generate > / * + - <= => !== operators + boost::ordered_field_operators, + // generate postfix ++ -- + boost::unit_steppable + { + + public: + + /** + * The Units + **/ + enum class Unit { B, K, M, G, T, P, E, Z, Y }; + + private: + + /** + * The size (in bytes) + * @see https://www.boost.org/doc/libs/release/libs/multiprecision/doc/html/index.html + **/ + boost::multiprecision::cpp_int _size; + + public: + + static const boost::multiprecision::cpp_int KB; + static const boost::multiprecision::cpp_int MB; + static const boost::multiprecision::cpp_int GB; + static const boost::multiprecision::cpp_int TB; + static const boost::multiprecision::cpp_int PB; + static const boost::multiprecision::cpp_int EB; + // these do not fit long long anymore! + static const boost::multiprecision::cpp_int ZB; + static const boost::multiprecision::cpp_int YB; + + /** + * Return ammount of bytes in Unit. + **/ + static boost::multiprecision::cpp_int factor( const Unit unit_r ) { + switch ( unit_r ) { + case Unit::Y: return YB; + case Unit::Z: return ZB; + case Unit::E: return EB; + case Unit::P: return PB; + case Unit::T: return TB; + case Unit::G: return GB; + case Unit::M: return MB; + case Unit::K: return KB; + case Unit::B: break; + } + return 1; + } + + /** + * String representation of Unit. + **/ + static const char * unit( const Unit unit_r ) { + switch ( unit_r ) { + case Unit::Y: return "YiB"; + case Unit::Z: return "ZiB"; + case Unit::E: return "EiB"; + case Unit::P: return "PiB"; + case Unit::T: return "TiB"; + case Unit::G: return "GiB"; + case Unit::M: return "MiB"; + case Unit::K: return "KiB"; + case Unit::B: break; + } + return "B"; + } + + public: + + /** + * Construct from size in certain unit. + * E.g. FSize( 1, FSize::Unit::K ) makes 1024 Byte. + **/ + FSize( const boost::multiprecision::cpp_int &size_r = 0, const Unit unit_r = Unit::B) + : _size( boost::multiprecision::cpp_int(size_r) * factor( unit_r ) ) + {} + + /** + * Construct from size in Byte. + * @param size_r the initial value + **/ + FSize( double size_r ) + : _size( size_r ) + {} + + /** + Construct from string containing a number in given unit. + * @param sizeStr input string - must contain *only* numbers + * @param unit_r optional unit, bytes by default + * @throws std::runtime_error if the string contains any non numeric characters, + * even a trailing white space! + */ + FSize( const std::string &sizeStr, const Unit unit_r = Unit::B ); + + /** + * Conversions to native data types - only explicit as it might overflow + * If the value is out of range then the behavior depends on the boost version + * - 1.67 - the min/max values for the corresponding type are returned + * - 1.66 - returns just the lower bits + **/ + explicit operator long long() const { return static_cast(_size); } + explicit operator int() const { return static_cast(_size); } + explicit operator double() const { return static_cast(_size); } + + operator boost::multiprecision::cpp_int() const { return _size; } + boost::multiprecision::cpp_int in_unit(const Unit unit_r) const { return _size / factor( unit_r ); } + + // unary minus + FSize operator-() const { return FSize(-_size); } + FSize & operator+=( const FSize &rhs ) { _size += boost::multiprecision::cpp_int(rhs); return *this; } + FSize & operator-=( const FSize &rhs ) { _size -= boost::multiprecision::cpp_int(rhs); return *this; } + FSize & operator*=( const FSize &rhs ) { _size *= boost::multiprecision::cpp_int(rhs); return *this; } + FSize & operator/=( const FSize &rhs ) { _size /= boost::multiprecision::cpp_int(rhs); return *this; } + + bool operator<( const FSize &rhs ) const { return _size < boost::multiprecision::cpp_int(rhs); } + bool operator==( const FSize &rhs ) const { return _size == boost::multiprecision::cpp_int(rhs); } + + // ++operator (the prefix variant) + FSize & operator++() { _size += 1; return *this; } + // --operator (the prefix variant) + FSize & operator--() { _size -= 1; return *this; } + + /** + * Adjust size to multiple of blocksize_r + **/ + FSize & fillBlock( FSize blocksize_r = boost::multiprecision::cpp_int(KB) ); + + /** + * Return a new size adjusted to multiple of blocksize_r + **/ + FSize fullBlock( FSize blocksize_r = boost::multiprecision::cpp_int(KB) ) const + { + FSize ret( _size ); + return ret.fillBlock( blocksize_r ); + } + + /** + * Return the best unit for string representation. + **/ + Unit bestUnit() const; + + /** + * Used as precision argument to form(), the 'best' precision according to + * Unist is chosen. + **/ + static const unsigned bestPrec = (unsigned)-1; + + /** + * Return string representation in given Unit. Parameter fw and + * prec denote field width and precision as in a "%*.*f" printf + * format string. Avalue of bestPrec automatically picks an + * appropriate precision depending on the unit. + * If showunit ist true, the string representaion + * of Unit is appended separated by a single blank. + * + * If Unit is Byte, precision is set to zero. + **/ + std::string form( const Unit unit_r, unsigned fw = 0, unsigned prec = bestPrec, const bool showunit = true ) const; + + /** + * Return string representation in bestUnit. + **/ + std::string form( unsigned fw = 0, unsigned prec = bestPrec, const bool showunit = true ) const { + return form( bestUnit(), fw, prec, showunit ); + } + + /** + * Default string representation (precision 1 and unit appended). + **/ + std::string asString() const; +}; + +// stream operators +std::ostream& operator<<(std::ostream &ostr, const FSize&); +std::ostream& operator<<(std::ostream &ostr, const FSize::Unit); + +#endif // _FSize_h_ diff --git a/src/ImplPtr.h b/src/ImplPtr.h new file mode 100644 index 0000000..c9007d9 --- /dev/null +++ b/src/ImplPtr.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: ImplPtr.h + + Author: Michael Andres + +/-*/ + +#ifndef ImplPtr_h +#define ImplPtr_h + +#include +#include + +/** + * Helper template class for implementation pointers (pointers to a private + * class or structure that hold the member variables of a higher-level class + * that is part of a public API). + * + * This pointer class maintains constness of its parent class, i.e. if it is + * used in a const class the class this pointer points to will also be const. + * + * This class automatically deletes the class it points to in its destructor. + **/ +template +class ImplPtr : private boost::noncopyable +{ +#if defined( BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS ) || defined( BOOST_NO_CXX11_NULLPTR ) + typedef typename boost::scoped_ptr<_Impl>::unspecified_bool_type unspecified_bool_type; +#endif + +public: + typedef _Impl element_type; + + explicit + ImplPtr( _Impl * impl_r = 0 ) : _impl( impl_r ) {} + +public: + void reset( _Impl * impl_r = 0 ) { _impl.reset( impl_r ); } + + void swap( ImplPtr rhs ) { _impl.swap( rhs._impl ); } + +public: +#if defined( BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS ) || defined( BOOST_NO_CXX11_NULLPTR ) + operator unspecified_bool_type() const { return _impl; } +#else + explicit operator bool () const { return _impl.get() != 0; } +#endif + + const _Impl & operator*() const { return *_impl; } + const _Impl * operator->() const { return _impl.get(); } + const _Impl * get() const { return _impl.get(); } + + _Impl & operator*() { return *_impl; } + _Impl * operator->() { return _impl.get(); } + _Impl * get() { return _impl.get(); } + +private: + boost::scoped_ptr<_Impl> _impl; +}; + +template +inline bool operator==( ImplPtr<_Impl> & lhs, ImplPtr<_Impl> & rhs ) { return lhs.get() == rhs.get(); } + +template +inline bool operator!=( ImplPtr<_Impl> & lhs, ImplPtr<_Impl> & rhs ) { return lhs.get() != rhs.get(); } + +template +inline bool operator< ( ImplPtr<_Impl> & lhs, ImplPtr<_Impl> & rhs ) { return lhs.get() < rhs.get(); } + +#endif // ImplPtr_h diff --git a/src/Notes.h b/src/Notes.h new file mode 100644 index 0000000..9a16dcd --- /dev/null +++ b/src/Notes.h @@ -0,0 +1,43 @@ +/* + Copyright (C) 2014 SUSE LLC + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ +/** +@page notes1 Notes about Initialization + +@section Important entry points + +- YUI::widgetFactory() +- YUI::ui() + +@section What happens on initialization + +YUI::ui() +calls YUI::ensureUICreated() +calls YUILoader::loadUI +calls YUILoader::loadPlugin. +That instantiates YUIPlugin(string plugin_name) and +calls its YUIPlugin::locateSymbol "_Z8createUIb" + (mangled createUI(bool) ) +to produce a YUI * (* createUIFunction_t)(bool withThreads) +which is called. Its result is discarded, but YUI::_ui gets initialized +by the YUI::YUI ctor called by the derived ctor. + +YUIPlugin calls dlopen, but dlclose is not called by default, +and actually proably never. + +@section Utility classes + +- YCommandLine + + */ diff --git a/src/TreeItem.h b/src/TreeItem.h new file mode 100644 index 0000000..8780f49 --- /dev/null +++ b/src/TreeItem.h @@ -0,0 +1,315 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: TreeItem.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef TreeItem_h +#define TreeItem_h + +#include + + + + +/** + * Template class for tree items that can handle tree children in a + * generic way - firstChild(), next() and parent(). Each item stores one value + * of type 'PAYLOAD'. + * + * Class 'PAYLOAD' needs to provide operator=(). + **/ +template class TreeItem +{ +public: + + /** + * Constructor. Creates a new tree item with value "val" and inserts it + * ( without maintaining any meaningful sort order! ) into the children list + * of "parent". + **/ + TreeItem ( const PAYLOAD & val, + TreeItem * parent = 0 ) + : _value( val ) + , _parent( parent ) + , _next(0) + , _firstChild(0) + { + if ( _parent ) + _parent->addChild( this ); + } + + +protected: + + /** + * Constructor to be called for derived classes: Decide whether or not to + * automatically insert this item into the parent's children list. Useful + * for derived classes that want to maintain a specific sort order among + * children. + **/ + TreeItem ( PAYLOAD val, + bool autoAddChild, + TreeItem * parent = 0 ) + : _value( val ) + , _parent( parent ) + , _next(0) + , _firstChild(0) + { + if ( _parent && autoAddChild ) + _parent->addChild( this ); + } + + +private: + /** + * Private ( i.e. disabled ) copy constructor and operator=() + * - neither makes any sense with this class. + **/ + TreeItem ( const TreeItem & ) {} + TreeItem & operator= ( const TreeItem & ) {} + + +public: + + /** + * Destructor. Takes care of children - they will be deleted along with + * this item. + **/ + virtual ~TreeItem () + { + TreeItem * child = firstChild(); + + while ( child ) + { + TreeItem * lastChild = child; + child = child->next(); + delete lastChild; + } + } + + + /** + * Returns this item's value, the "payload". + **/ + const PAYLOAD & value() const { return _value; } + + /** + * Set this item's value, the "payload". + * + * If the sort order among children of one level is important, overwrite + * this method and change the sort order according to the new value. + * The template class itself never calls this. + **/ + void setValue( PAYLOAD newValue ) { _value = newValue; } + + /** + * Returns this item's parent or 0 if there is none. + **/ + TreeItem * parent() const { return _parent; } + + /** + * Returns this item's next sibling or 0 if there is none. + **/ + TreeItem * next() const { return _next; } + + /** + * Returns this item's first child or 0 if there is none. + **/ + TreeItem * firstChild() const { return _firstChild; } + + /** + * Sets this item's parent. + **/ + void setParent( TreeItem * newParent ) { _parent = newParent; } + + /** + * Sets this item's next sibling. + **/ + void setNext( TreeItem * newNext ) { _next = newNext; } + + /** + * Sets this item's first child. + **/ + void setFirstChild( TreeItem * newFirstChild ) + { _firstChild = newFirstChild; } + + + /** + * Add a child to the internal children list - usually called from within + * the child's default constructor. + * + * This default method does not maintain any meaningful sorting order - + * derived classes that require this might want to use the other + * constructor ( with 'autoAddChild' set to 'false' ) take care of child + * insertion themselves. + **/ + void addChild( TreeItem * newChild ) + { + if ( newChild ) + { + newChild->setNext( firstChild() ); + setFirstChild( newChild ); + } + } + + +protected: + + PAYLOAD _value; + TreeItem * _parent; + TreeItem * _next; + TreeItem * _firstChild; +}; + + + +/** + * Template class for tree items that maintain sort order. + * + * Class 'PAYLOAD' to provide operator<() in addition to what template + *'TreeItem' requires. + **/ +template class SortedTreeItem: public TreeItem +{ +public: + + /** + * Constructor. Creates a new tree item with value "val" and inserts it in + * ascending sort order into the children list of "parent". + **/ + SortedTreeItem( PAYLOAD val, + SortedTreeItem * parentItem = 0 ) + : TreeItem ( val, false, parentItem ) + { + if ( parentItem ) + { + // Hopefully we have a SortedTreeItem parent + SortedTreeItem * sortParent = + dynamic_cast *> ( parentItem ); + + if ( sortParent ) + sortParent->insertChildSorted( this ); + else // no SortedTreeItem parent - add unsorted + parentItem->addChild( this ); + } + } + + + /** + * Destructor. + **/ + virtual ~SortedTreeItem () {} + + + /** + * Insert a child into the internal children list in ascending sort order. + * Called from the new child's constructor, thus 'public'. + **/ + void insertChildSorted( SortedTreeItem * newChild ) + { + if ( ! newChild ) + return; + + if ( ! firstChild() || + newChild->value() < firstChild()->value() ) + { + // Insert as first child + + newChild->setNext( firstChild() ); + this->setFirstChild( newChild ); + } + else + { + // Search correct place to insert + + TreeItem * child = firstChild(); + + while ( child->next() && + child->next()->value() < newChild->value() ) + { + child = child->next(); + } + + + // Insert after 'child' + + newChild->setNext( child->next() ); + child->setNext( newChild ); + } + } + + + /** + * Returns this item's parent or 0 if there is none. + **/ + SortedTreeItem * parent() const + { return ( SortedTreeItem * ) TreeItem::_parent; } + + /** + * Returns this item's next sibling or 0 if there is none. + **/ + SortedTreeItem * next() const + { return ( SortedTreeItem * ) TreeItem::_next; } + + /** + * Returns this item's first child or 0 if there is none. + **/ + SortedTreeItem * firstChild() const + { return ( SortedTreeItem * ) TreeItem::_firstChild; } + + +private: + + /** + * Private ( i.e. disabled ) copy constructor and operator=() + * - neither makes any sense with this class. + **/ + SortedTreeItem ( const SortedTreeItem & ) {} + SortedTreeItem & operator= ( const SortedTreeItem & ) {} +}; + + + +/** + * Find a direct child ( i.e., non-recursive ) with value "searchVal". + * Returns 0 if there is no such child. + **/ +template inline +ITEM * +findDirectChild( ITEM * item, PAYLOAD searchVal ) +{ + TreeItem * child = item->firstChild(); + + while ( child ) + { + if ( child->value() == searchVal ) + return dynamic_cast ( child ); + + child = child->next(); + } + + return 0; +} + + + +#endif // TreeItem_h diff --git a/src/YAlignment.cc b/src/YAlignment.cc new file mode 100644 index 0000000..2bfa2c5 --- /dev/null +++ b/src/YAlignment.cc @@ -0,0 +1,396 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YAlignment.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YAlignment.h" +#include "YBothDim.h" +#include "YPath.h" + +#include "Libyui_config.h" + + + + +struct YAlignmentPrivate +{ + /** + * Constructor. + **/ + YAlignmentPrivate( YAlignmentType horAlign, + YAlignmentType vertAlign ) + : leftMargin(0) + , rightMargin(0) + , topMargin(0) + , bottomMargin(0) + , minWidth(0) + , minHeight(0) + { + alignment.hor = horAlign; + alignment.vert = vertAlign; + } + + // + // Data Members + // + + int leftMargin; + int rightMargin; + int topMargin; + int bottomMargin; + + int minWidth; + int minHeight; + + std::string backgroundPixmap; + + YBothDim alignment; +}; + + + + +YAlignment::YAlignment( YWidget * parent, + YAlignmentType horAlign, + YAlignmentType vertAlign ) + : YSingleChildContainerWidget( parent ) + , priv( new YAlignmentPrivate( horAlign, vertAlign ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YAlignment::~YAlignment() +{ + // NOP +} + + +YAlignmentType +YAlignment::alignment( YUIDimension dim ) const +{ + return priv->alignment[ dim ]; +} + + +int YAlignment::leftMargin() const +{ + return priv->leftMargin; +} + + +int YAlignment::rightMargin() const +{ + return priv->rightMargin; +} + + +int YAlignment::topMargin() const +{ + return priv->topMargin; +} + + +int YAlignment::bottomMargin() const +{ + return priv->bottomMargin; +} + + +void YAlignment::setLeftMargin( int margin ) +{ + priv->leftMargin = margin; +} + + +void YAlignment::setRightMargin( int margin ) +{ + priv->rightMargin = margin; +} + + +void YAlignment::setTopMargin( int margin ) +{ + priv->topMargin = margin; +} + + +void YAlignment::setBottomMargin( int margin ) +{ + priv->bottomMargin = margin; +} + + +int YAlignment::minWidth() const +{ + return priv->minWidth; +} + + +int YAlignment::minHeight() const +{ + return priv->minHeight; +} + + +void YAlignment::setMinWidth( int width ) +{ + priv->minWidth = width; +} + + +void YAlignment::setMinHeight( int height ) +{ + priv->minHeight = height; +} + + +std::string YAlignment::backgroundPixmap() const +{ + return priv->backgroundPixmap; +} + + +void YAlignment::addChild( YWidget * child ) +{ + YSingleChildContainerWidget::addChild( child ); + + if ( minWidth() > 0 ) child->setStretchable( YD_HORIZ, true ); + if ( minHeight() > 0 ) child->setStretchable( YD_VERT , true ); +} + + +bool YAlignment::stretchable( YUIDimension dim ) const +{ + if ( alignment( dim ) == YAlignUnchanged && hasChildren() ) + return firstChild()->stretchable( dim ); + else + return true; +} + + +int YAlignment::preferredWidth() +{ + if ( ! hasChildren() ) + return minWidth(); + + int preferredWidth = firstChild()->preferredWidth(); + preferredWidth += leftMargin() + rightMargin(); + + return std::max( minWidth(), preferredWidth ); +} + + +int YAlignment::preferredHeight() +{ + if ( ! hasChildren() ) + return minHeight(); + + int preferredHeight = firstChild()->preferredHeight(); + preferredHeight += topMargin() + bottomMargin(); + + return std::max( minHeight(), preferredHeight ); +} + + +void YAlignment::setSize( int newWidth, int newHeight ) +{ + if ( ! hasChildren() ) + { + yuiError() << "No child in " << this << std::endl; + return; + } + + + YBothDim newSize; + newSize.hor = newWidth; + newSize.vert = newHeight; + + YBothDim offset; + offset.hor = leftMargin(); + offset.vert = topMargin(); + + YBothDim totalMargin; + totalMargin.hor = leftMargin() + rightMargin(); + totalMargin.vert = topMargin() + bottomMargin(); + + YBothDim newChildSize; + YBothDim newChildPos; + + YUIDimension dim = YD_HORIZ; + while ( true ) // only toggle + { + int childPreferredSize = firstChild()->preferredSize( dim ); + int preferredSize = childPreferredSize + totalMargin[ dim ]; + + if ( newSize[ dim ] >= preferredSize ) + // Optimum case: enough space for the child and all margins + { + if ( firstChild()->stretchable( dim ) && + ( alignment( dim ) == YAlignUnchanged || + stretchable( dim ) ) ) // special case: promote child stretchability if `opt(`?stretch) set + { + newChildSize[ dim ] = newSize[ dim ] - totalMargin[ dim ]; + } + else + { + newChildSize[ dim ] = childPreferredSize; + } + } + else if ( newSize[ dim ] >= childPreferredSize ) + // Still enough space for the child, but not for all margins + { + newChildSize[ dim ] = childPreferredSize; // Give the child as much space as it needs + + // Reduce the margins + + if ( totalMargin[ dim ] > 0 ) // Prevent division by zero + { + // Redistribute remaining space according to margin ratio + // (disregarding integer rounding errors - we don't care about one pixel) + + int remaining = newSize[ dim ] - childPreferredSize; + offset [ dim ] = remaining * offset[ dim ] / totalMargin[ dim ]; + totalMargin[ dim ] = remaining; + } + + } + else // Not even enough space for the child - forget about the margins + { + newChildSize[ dim ] = newSize[ dim ]; + offset [ dim ] = 0; + totalMargin [ dim ] = 0; + } + + + switch ( alignment( dim ) ) + { + case YAlignCenter: + newChildPos[ dim ] = ( newSize[ dim ] - newChildSize[ dim ] - totalMargin[ dim ] ) / 2; + break; + + case YAlignUnchanged: + case YAlignBegin: + newChildPos[ dim ] = 0; + break; + + case YAlignEnd: + newChildPos[ dim ] = newSize[ dim ] - newChildSize[ dim ] - totalMargin[ dim ]; + break; + } + + newChildPos[ dim ] += offset[ dim ]; + + // we need to get out of this loop after the second run + if (dim == YD_HORIZ) + dim = YD_VERT; + else + break; + } + + firstChild()->setSize( newChildSize.hor, newChildSize.vert ); + moveChild( firstChild(), newChildPos.hor, newChildPos.vert ); + +#if 0 + yuiDebug() << "setSize( alignment, " << newWidth << ", " << newHeight << ")" << std::endl; + yuiDebug() << "setSize( child, " << newChildSize.hor << ", " << newChildSize.vert << ")" << std::endl; + yuiDebug() << "moveChild( " << newChildPos.hor << ", " << newChildPos.vert << ")" << std::endl; +#endif +} + + + +int YAlignment::totalMargins( YUIDimension dim ) const +{ + if ( dim == YD_HORIZ ) return leftMargin() + rightMargin(); + else return topMargin() + bottomMargin(); +} + + + +void YAlignment::setBackgroundPixmap( const std::string & pixmapFileName ) +{ + std::string pixmap = pixmapFileName; + + if ( pixmap.length() > 0 && + pixmap[0] != '/' && // Absolute path? + pixmap[0] != '.' ) // Path relative to $CWD ? + { + // Prepend theme dir + + YPath pix( THEMEDIR, pixmap ); + + pixmap = pix.path(); + } + + priv->backgroundPixmap = pixmap; +} + +const char * +YAlignment::widgetClass() const +{ + static const char *YAlignment_classes[3][5] = + { + {"YAlignment_Left", "YAlignment_HCenter", "YAlignment_Right", "YMarginBox", "YMinWidth"}, + {"YAlignment_Top", "YAlignment_VCenter", "YAlignment_Bottom", "YMarginBox", "YMinHeight"}, + {0, "YAlignment_HVCenter", 0, "YAlignment", "YMinSize"}, + }; + + int hIndex = 3; + int vIndex = 2; + + if ( priv->alignment.hor == YAlignBegin ) { vIndex = 0; hIndex = 0; } + else if ( priv->alignment.hor == YAlignEnd ) { vIndex = 0; hIndex = 2; } + else if ( priv->alignment.hor == YAlignCenter ) + { + vIndex = 0; hIndex = 1; + if ( priv->alignment.vert == YAlignCenter ) + vIndex = 2; + } + else if ( priv->alignment.vert == YAlignBegin ) { vIndex = 1; hIndex = 0; } + else if ( priv->alignment.vert == YAlignEnd ) { vIndex = 1; hIndex = 2; } + else if ( priv->alignment.vert == YAlignCenter ) { vIndex = 1; hIndex = 1; } + + if ( priv->alignment.hor == YAlignUnchanged && + priv->alignment.vert == YAlignUnchanged ) + { + if ( priv->leftMargin > 0 || + priv->rightMargin > 0 || + priv->topMargin > 0 || + priv->bottomMargin > 0 ) + { + vIndex = 0; hIndex = 3; + } + + if ( priv->minWidth > 0 || priv->minHeight > 0 ) + { + if ( priv->minWidth == 0 ) { vIndex = 1; hIndex = 4; } + else if ( priv->minHeight == 0 ) { vIndex = 0; hIndex = 4; } + else { vIndex = 2; hIndex = 4; } + } + } + return YAlignment_classes[vIndex][hIndex]; +} diff --git a/src/YAlignment.h b/src/YAlignment.h new file mode 100644 index 0000000..d716c77 --- /dev/null +++ b/src/YAlignment.h @@ -0,0 +1,210 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YAlignment.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YAlignment_h +#define YAlignment_h + +#include "YSingleChildContainerWidget.h" + + +class YAlignmentPrivate; + +/** + * Implementation of all the alignment widgets: + * + * - Left, Right, HCenter, + * - Top, Bottom, VCenter, + * - HVCenter + * - MinSize, MinWidth, MinHeight + **/ +class YAlignment : public YSingleChildContainerWidget +{ +protected: + /** + * Constructor. + **/ + YAlignment( YWidget * parent, + YAlignmentType horAlign, + YAlignmentType vertAlign ); + +public: + /** + * Destructor. + **/ + virtual ~YAlignment(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const; + + /** + * Return the alignment in the specified dimension. + **/ + YAlignmentType alignment( YUIDimension dim ) const; + + /** + * Return the left margin in pixels, the distance between the left edge of + * this alignment and the left edge of the child widget. + **/ + int leftMargin() const; + + /** + * Return the right margin in pixels, the distance between the right edge + * of this alignment and the right edge of the child widget. + **/ + int rightMargin() const; + + /** + * Return the top margin in pixels, the distance between the top edge of + * this alignment and the top edge of the child widget. + **/ + int topMargin() const; + + /** + * Return the bottom margin in pixels, the distance between the bottom + * edge of this alignment and the bottom edge of the child widget. + **/ + int bottomMargin() const; + + /** + * Return the sum of all margins in the specified dimension. + **/ + int totalMargins( YUIDimension dim ) const; + + /** + * Set the left margin in pixels. + **/ + void setLeftMargin( int margin ); + + /** + * Set the right margin in pixels. + **/ + void setRightMargin( int margin ); + + /** + * Set the top margin in pixels. + **/ + void setTopMargin( int margin ); + + /** + * Set the bottom margin in pixels. + **/ + void setBottomMargin( int margin ); + + /** + * Return the minimum width of this alignment or 0 if none is set. + * preferredWidth() will never return less than this value. + **/ + int minWidth() const; + + /** + * Return the minimum height of this alignment or 0 if none is set. + * preferredHeight() will never return less than this value. + **/ + int minHeight() const; + + /** + * Set the minimum width to return for preferredWidth(). + **/ + void setMinWidth( int width ); + + /** + * Set the minimum height to return for preferredHeight(). + **/ + void setMinHeight( int height ); + + /** + * Set a background pixmap. + * + * Derived classes may want to overwrite this. + * + * This parent method should be called first in the overwritten method to + * ensure path expansion is done as specified (prepend the theme path + * ("/usr/share/libyui/theme/") if the path doesn't start with "/" + * or "."). + **/ + virtual void setBackgroundPixmap( const std::string & pixmapFileName ); + + /** + * Return the name of the background pixmap or an empty string, if there + * is none. + **/ + std::string backgroundPixmap() const; + + /** + * Add a child widget. + * + * Reimplemented from YSingleChildContainerWidget to propagate + * stretchability down to the single child. + **/ + virtual void addChild( YWidget * child ); + + /** + * Move a child widget to a new position. + **/ + virtual void moveChild( YWidget *child, int newx, int newy ) = 0; + + /** + * Return this widget's stretchability. + * Reimplemented from YWidget. + * + * In an aligned dimension the widget is always stretchable. + * In an unchanged dimension the widget is stretchable if the + * child is stretchable. + **/ + virtual bool stretchable( YUIDimension dim ) const; + + /** + * Preferred width of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredWidth(); + + /** + * Preferred height of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredHeight(); + + /** + * Set the current size and move the child widget according to its + * alignment. + * + * Derived classes should reimplement this, but call this base class + * function in their own implementation. + **/ + virtual void setSize( int newWidth, int newHeight ); + + +protected: + + ImplPtr priv; +}; + + +#endif // YAlignment_h diff --git a/src/YApplication.cc b/src/YApplication.cc new file mode 100644 index 0000000..00c2f25 --- /dev/null +++ b/src/YApplication.cc @@ -0,0 +1,300 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YApplication.cc + + Author: Stefan Hundhammer + +/-*/ + +#include // setlocale() +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YApplication.h" +#include "YDialog.h" +#include "YUIException.h" +#include "YShortcut.h" +#include "YUI.h" +#include "YItem.h" +#include "YCommandLine.h" + +using std::endl; + +typedef std::map YFunctionKeyMap; + + +struct YApplicationPrivate +{ + YApplicationPrivate() + : productName( "SUSE Linux" ) + , reverseLayout( false ) + , showProductLogo( false ) + {} + + std::string productName; + bool reverseLayout; + std::string applicationTitle; + std::string applicationIcon; + YFunctionKeyMap defaultFunctionKey; + YIconLoader* iconLoader; + std::map releaseNotes; + bool showProductLogo; +}; + + +YApplication::YApplication() + : priv( new YApplicationPrivate() ) +{ + YUI_CHECK_NEW( priv ); + priv->iconLoader = new YIconLoader(); + YCommandLine cmdLine; // Retrieve command line args from /proc//cmdline + if ( cmdLine.argc() > 0 ) + priv->applicationTitle = cmdLine.arg(0); +} + + +YApplication::~YApplication() +{ + // NOP +} + + +YWidget * +YApplication::findWidget( YWidgetID * id, bool doThrow ) const +{ + YDialog * dialog = YDialog::currentDialog( doThrow ); + + if ( ! dialog ) // has already thrown if doThrow == true + return 0; + + return dialog->findWidget( id, doThrow ); +} + + +std::string +YApplication::iconBasePath() const +{ + return priv->iconLoader->iconBasePath(); +} + + +void +YApplication::setIconBasePath( const std::string & newIconBasePath ) +{ + priv->iconLoader->setIconBasePath ( newIconBasePath ); +} + +YIconLoader * +YApplication::iconLoader() +{ + return priv->iconLoader; +} + +void +YApplication::setProductName( const std::string & productName ) +{ + priv->productName = productName; +} + + +std::string +YApplication::productName() const +{ + return priv->productName; +} + +void +YApplication::setReleaseNotes( const std::map & relNotes ) +{ + priv->releaseNotes = relNotes; +} + +std::map +YApplication::releaseNotes() const +{ + return priv->releaseNotes; +} + +void +YApplication::setShowProductLogo( bool show ) +{ + priv->showProductLogo = show; +} + +bool +YApplication::showProductLogo() const +{ + return priv->showProductLogo; +} + +void +YApplication::setReverseLayout( bool reverse ) +{ + priv->reverseLayout = reverse; +} + + +bool YApplication::reverseLayout() const +{ + return priv->reverseLayout; +} + + +int +YApplication::defaultFunctionKey( const std::string & label ) const +{ + YFunctionKeyMap::const_iterator result = + priv->defaultFunctionKey.find( YShortcut::cleanShortcutString( label ) ); + + if ( result == priv->defaultFunctionKey.end() ) + return 0; + else + return result->second; +} + + +void +YApplication::setDefaultFunctionKey( const std::string & label, int fkey ) +{ + if ( fkey > 0 ) + priv->defaultFunctionKey[ YShortcut::cleanShortcutString( label ) ] = fkey; + else + YUI_THROW( YUIException( "Bad function key number" ) ); +} + + +void +YApplication::clearDefaultFunctionKeys() +{ + priv->defaultFunctionKey.clear(); +} + + +void +YApplication::setLanguage( const std::string & language, const std::string & encoding ) +{ + std::string lang = language; + + if ( ! encoding.empty() ) + { + lang += "."; + lang += encoding; + } + + setenv( "LANG", lang.c_str(), 1 ); // 1 : replace + setlocale( LC_NUMERIC, "C" ); // but always format numbers with "." + + yuiMilestone() << "Setting language to " << lang << endl; +} + + +std::string +YApplication::language( bool stripEncoding ) const +{ + const char *lang_env = getenv( "LANG" ); + + if ( ! lang_env ) + return ""; + + std::string lang( lang_env ); + + if ( stripEncoding ) + { + std::string::size_type pos = lang.find_first_of( ".@" ); + + if ( pos != std::string::npos ) // if encoding etc. specified + { + lang = lang.substr( 0, pos ); // remove it + } + } + + return lang; +} + + +std::string +YApplication::glyph( const std::string & sym ) +{ + if ( sym == YUIGlyph_ArrowLeft ) return ( reverseLayout() ? "->" : "<-" ); + else if ( sym == YUIGlyph_ArrowRight ) return ( reverseLayout() ? "<-" : "->" ); + else if ( sym == YUIGlyph_ArrowUp ) return ( "^" ); + else if ( sym == YUIGlyph_ArrowDown ) return ( "v" ); + else if ( sym == YUIGlyph_CheckMark ) return ( "x" ); + else if ( sym == YUIGlyph_BulletArrowRight ) return ( "=>" ); + else if ( sym == YUIGlyph_BulletCircle ) return ( "o" ); + else if ( sym == YUIGlyph_BulletSquare ) return ( "[]" ); + else // unknown glyph symbol + { + yuiError() << "Unknown glyph `" << sym << endl; + return ""; + } +} + +bool +YApplication::openContextMenu( const YItemCollection & itemCollection ) +{ + YUI_THROW( YUIUnsupportedWidgetException( "ContextMenu" ) ); + return false; +} + + + +int +YApplication::deviceUnits( YUIDimension dim, float layoutUnits ) +{ + return (int) ( layoutUnits + 0.5 ); +} + + +float +YApplication::layoutUnits( YUIDimension dim, int deviceUnits ) +{ + return (float) deviceUnits; +} + + +int +YApplication::runInTerminal ( const std::string & module ) +{ + yuiError() << "Not in text mode: Cannot run external program in terminal." << endl; + + return -1; +} + +void YApplication::setApplicationTitle(const std::string &title) +{ + priv->applicationTitle = title; +} + +const std::string &YApplication::applicationTitle() const +{ + return priv->applicationTitle; +} + +void YApplication::setApplicationIcon(const std::string &icon) +{ + priv->applicationIcon = icon; +} +const std::string &YApplication::applicationIcon() const +{ + return priv->applicationIcon; +} + diff --git a/src/YApplication.h b/src/YApplication.h new file mode 100644 index 0000000..5553aa5 --- /dev/null +++ b/src/YApplication.h @@ -0,0 +1,448 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YApplication.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YApplication_h + +#include +#include +#include "YUI.h" +#include "ImplPtr.h" +#include "YMenuItem.h" +#include "YIconLoader.h" + + + +class YWidget; +class YWidgetID; +struct YApplicationPrivate; + + +/** + * Class for application-wide values and functions. + * This is a singleton. Access and create it via the static functions in YUI. + **/ +class YApplication +{ +protected: + + friend class YUI; + /** + * Constructor. + * + * Use YUI::app() to get the singleton for this class. + **/ + YApplication(); + + /** + * Destructor. + **/ + virtual ~YApplication(); + +public: + + /** + * Find a widget in the topmost dialog by its ID. + * + * If there is no widget with that ID (or no dialog at all), this function + * throws a YUIWidgetNotFoundException if 'doThrow' is 'true'. It returns 0 + * if 'doThrow' is 'false'. + **/ + YWidget * findWidget( YWidgetID * id, bool doThrow = true ) const; + + /** + * Get the base path for icons used by the UI. Selection widgets like + * YSelectionBox, YComboBox, etc. or YWizard prepend this to icon + * specifications that don't use an absolute path. + **/ + virtual std::string iconBasePath() const; + + /** + * Set the icon base path. + **/ + virtual void setIconBasePath( const std::string & newIconBasePath ); + + YIconLoader *iconLoader(); + + /** + * Return the default function key number for a widget with the specified + * label or 0 if there is none. Any keyboard shortcuts that may be + * contained in 'label' are stripped away before any comparison. + * + * The basic idea behind this concept is to have an easy default mapping + * from buttons etc. with the same semantics to function keys: + * + * "OK" -> F10 + * "Accept" -> F10 + * "Yes" -> F10 + * "Next" -> F10 + * + * "Cancel" -> F9 + * "No" -> F9 + * ... + * + * This function returns 10 for F10, F for F9 etc.; + * 0 means "no function key". + **/ + int defaultFunctionKey( const std::string & label ) const; + + /** + * Add a mapping from the specified label to the specified F-key number. + * This is the counterpart to defaultFunctionKey(). + * + * This only affects widgets that are created after this call. + **/ + void setDefaultFunctionKey( const std::string & label, int fkey ); + + /** + * Clear all previous label-to-function-key mappings. + **/ + void clearDefaultFunctionKeys(); + + /** + * Set language and encoding for the locale environment ($LANG). + * + * This affects UI-internal translations (e.g. for predefined dialogs like + * file selection), encoding and fonts. + * + * 'language' is the ISO short code ("de_DE", "en_US", ...). + * + * 'encoding' an (optional) encoding ("utf8", ...) that will be appended if + * present. + * + * Derived classes can overwrite this method, but they should call this + * base class method at the beginning of the new implementation. + **/ + virtual void setLanguage( const std::string & language, + const std::string & encoding = std::string() ); + + /** + * Return the current language from the locale environment ($LANG). + * If 'stripEncoding' is true, any encoding (".utf8" etc.) is removed. + **/ + std::string language( bool stripEncoding = false ) const; + + /** + * Return a string for a named glyph: + * + * YUIGlyph_ArrowLeft + * YUIGlyph_ArrowRight + * YUIGlyph_ArrowUp + * YUIGlyph_ArrowDown + * YUIGlyph_CheckMark + * YUIGlyph_BulletArrowRight + * YUIGlyph_BulletCircle + * YUIGlyph_BulletSquare + * + * Using this is discouraged in new applications. + * This method is available for backward compatibility. + * + * This default implementation returns simple textual representations for + * each glyph simbol (e.g., "->" for YUIGlyphArrorRight). + * + * Derived classes are free to overwrite this. It does not make sense to + * call this base class method in a new implementation. + **/ + virtual std::string glyph( const std::string & glyphSymbolName ); + + /** + * Open a directory selection box and prompt the user for an existing + * directory. + * + * 'startDir' is the initial directory that is displayed. + * + * 'headline' is an explanatory text for the directory selection box. + * Graphical UIs may omit that if no window manager is running. + * + * Returns the selected directory name + * or an empty string if the user canceled the operation. + * + * Derived classes are required to implement this. + **/ + virtual std::string askForExistingDirectory( const std::string & startDir, + const std::string & headline ) = 0; + + /** + * Open a file selection box and prompt the user for an existing file. + * + * 'startWith' is the initial directory or file. + * + * 'filter' is one or more blank-separated file patterns, e.g. + * "*.png *.jpg" + * + * 'headline' is an explanatory text for the file selection box. + * Graphical UIs may omit that if no window manager is running. + * + * Returns the selected file name + * or an empty string if the user canceled the operation. + * + * Derived classes are required to implement this. + **/ + virtual std::string askForExistingFile( const std::string & startWith, + const std::string & filter, + const std::string & headline ) = 0; + + /** + * Open a file selection box and prompt the user for a file to save data + * to. Automatically asks for confirmation if the user selects an existing + * file. + * + * 'startWith' is the initial directory or file. + * + * 'filter' is one or more blank-separated file patterns, e.g. + * "*.png *.jpg" + * + * 'headline' is an explanatory text for the file selection box. + * Graphical UIs may omit that if no window manager is running. + * + * Returns the selected file name + * or an empty string if the user canceled the operation. + * + * Derived classes are required to implement this. + **/ + virtual std::string askForSaveFileName( const std::string & startWith, + const std::string & filter, + const std::string & headline ) = 0; + + /** + * Open a context menu for a widget + * + * 'itemCollection' describes the menu structure + * + * Returns true on success (otherwise false). + * + * Derived classes are free to overwrite this. + **/ + virtual bool openContextMenu( const YItemCollection & itemCollection ); + + + /** + * Set the current product name ("openSUSE", "SLES", ...). + * This name will be expanded in help texts when the &product; entity is + * used. + * + * Derived classes can overwrite this method, but they should call this + * base class method in the new implementation. + **/ + virtual void setProductName( const std::string & productName ); + + /** + * Get the current product name ("openSUSE", "SLES", ...). + **/ + std::string productName() const; + + /** + * Set release notes; map product => text + * + */ + void setReleaseNotes( const std::map & relNotes ); + + /** + * Get the current release notes map + **/ + std::map releaseNotes() const; + + /** + * Set whether the product logo (in top bar) should be shown + */ + void setShowProductLogo( bool show ); + + /** + * Return true if product logo should be shown + */ + bool showProductLogo() const; + + /** + * Convert logical layout spacing units into device dependent units. + * A default size dialog is assumed to be 80x25 layout spacing units. + * + * Derived classes may want to reimplement this method. + **/ + virtual int deviceUnits( YUIDimension dim, float layoutUnits ); + + /** + * Convert device dependent units into logical layout spacing units. + * A default size dialog is assumed to be 80x25 layout spacing units. + * + * Derived classes may want to reimplement this method. + **/ + virtual float layoutUnits( YUIDimension dim, int deviceUnits ); + + /** + * Set reverse layout for Arabic / Hebrew support. + * + * Derived classes can overwrite this method, but they should call this + * base class method in the new implementation. + **/ + virtual void setReverseLayout( bool reverse ); + + /** + * Returns 'true' if widget geometry should be reversed for languages that + * have right-to-left writing direction (Arabic, Hebrew). + **/ + bool reverseLayout() const; + + /** + * Change the (mouse) cursor to indicate busy status. + * This default implementation does nothing. + **/ + virtual void busyCursor() {} + + /** + * Change the (mouse) cursor back from busy status to normal. + * This default implementation does nothing. + **/ + virtual void normalCursor() {} + + /** + * Make a screen shot and save it to the specified file. + * This default implementation does nothing. + **/ + virtual void makeScreenShot( const std::string & fileName ) {} + + /** + * Beep. + * This default implementation does nothing. + **/ + virtual void beep() {} + + + // + // NCurses (text mode) specific + // + + /** + * Redraw the screen. + * This default implementation does nothing. + **/ + virtual void redrawScreen() {} + + /** + * Initialize the (text) console keyboard. + * This default implementation does nothing. + **/ + virtual void initConsoleKeyboard() {} + + /** + * Set the (text) console font according to the current encoding etc. + * See the setfont(8) command and the console HowTo for details. + * + * This default implementation does nothing. + **/ + virtual void setConsoleFont( const std::string & console_magic, + const std::string & font, + const std::string & screen_map, + const std::string & unicode_map, + const std::string & language ) + {} + + /** + * Run a shell command (typically an interactive program using NCurses) + * in a terminal (window). + * + * This is useful for text UIs (e.g., NCurses) that need special + * preparation prior to running an NCurses-based application and special + * clean-up afterwards. + * + * This default implementation logs an error and returns -1. + **/ + virtual int runInTerminal( const std::string & command ); + + + /// @{ + /** + * To mix TUI (NCurses) with stdio, enclose the UI parts + * within openUI/closeUI + * + * This default implementation does nothing. + */ + virtual void openUI() {} + virtual void closeUI() {} + /// @} + + // + // Display information. + // + // Width and height are returned in the the UI's native dimension: + // Pixels for graphical UIs, character cells for text UIs. + // -1 means "value cannot be obtained" for int functions. + // + // Derived classes are required to implement these functions. + // + + virtual int displayWidth() = 0; + virtual int displayHeight() = 0; + virtual int displayDepth() = 0; + virtual long displayColors() = 0; + + // Size of main dialogs + virtual int defaultWidth() = 0; + virtual int defaultHeight() = 0; + + // + // UI capabilities + // + + virtual bool isTextMode() = 0; + virtual bool hasImageSupport() = 0; + virtual bool hasIconSupport() = 0; + virtual bool hasAnimationSupport() = 0; + virtual bool hasFullUtf8Support() = 0; + virtual bool richTextSupportsTable() = 0; + virtual bool leftHandedMouse() = 0; + virtual bool hasWizardDialogSupport() { return false; } + + + /** + * Set the application title + **/ + virtual void setApplicationTitle ( const std::string& title ); + + /** + * Get the application title + * + * Default title is the running command (argv[0]) + **/ + virtual const std::string& applicationTitle() const; + + /** + * Set the application Icon + **/ + virtual void setApplicationIcon ( const std::string& icon ); + + /** + * Get the application Icon + * + * Default icon is an empty string + **/ + virtual const std::string& applicationIcon() const; + +private: + + ImplPtr priv; + +}; + +#define YApplication_h + +#endif // YApplication_h diff --git a/src/YBarGraph.cc b/src/YBarGraph.cc new file mode 100644 index 0000000..7626049 --- /dev/null +++ b/src/YBarGraph.cc @@ -0,0 +1,241 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YBarGraph.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YBarGraph.h" + + + +#define CHECK_INDEX(index) \ + do \ + { \ + if ( (index) < 0 || \ + (index) >= (int) priv->segments.size() ) \ + { \ + YUI_THROW( YUIIndexOutOfRangeException( \ + (index), /* current */ \ + 0, /* min */ \ + (int) priv->segments.size() - 1 ) ); /* max */ \ + } \ + } while( 0 ) + + + +struct YBarGraphPrivate +{ + YBarGraphPrivate() + : updatesPending( false ) + , postponeUpdates( false ) + {} + + std::vector segments; + bool updatesPending; + bool postponeUpdates; +}; + + + + +YBarGraph::YBarGraph( YWidget * parent ) + : YWidget( parent ) + , priv( new YBarGraphPrivate() ) +{ + YUI_CHECK_NEW( priv ); + setDefaultStretchable( YD_HORIZ, true ); +} + + +YBarGraph::~YBarGraph() +{ + // NOP +} + + +void +YBarGraph::updateDisplay() +{ + priv->updatesPending = true; + + if ( ! priv->postponeUpdates ) + { + doUpdate(); + priv->updatesPending = false; + } +} + + +void +YBarGraph::addSegment( const YBarGraphSegment & segment ) +{ + priv->segments.push_back( segment ); + updateDisplay(); +} + + +void +YBarGraph::deleteAllSegments() +{ + priv->segments.clear(); + updateDisplay(); +} + + +const YBarGraphSegment & +YBarGraph::segment( int segmentIndex ) const +{ + CHECK_INDEX( segmentIndex ); + + return priv->segments[ segmentIndex ]; +} + + +int +YBarGraph::segments() +{ + return (int) priv->segments.size(); +} + + +void +YBarGraph::setValue( int segmentIndex, int newValue ) +{ + CHECK_INDEX( segmentIndex ); + + priv->segments[ segmentIndex ].setValue( newValue ); + updateDisplay(); +} + + +void +YBarGraph::setLabel( int segmentIndex, const std::string & newLabel ) +{ + CHECK_INDEX( segmentIndex ); + + priv->segments[ segmentIndex ].setLabel( newLabel ); + updateDisplay(); +} + + +void +YBarGraph::setSegmentColor( int segmentIndex, const YColor & color ) +{ + CHECK_INDEX( segmentIndex ); + + if ( color.isUndefined() ) + YUI_THROW( YUIException( "Invalid YColor" ) ); + + priv->segments[ segmentIndex ].setSegmentColor( color ); + updateDisplay(); +} + + +void +YBarGraph::setTextColor( int segmentIndex, const YColor & color ) +{ + CHECK_INDEX( segmentIndex ); + + if ( color.isUndefined() ) + YUI_THROW( YUIException( "Invalid YColor" ) ); + + priv->segments[ segmentIndex ].setTextColor( color ); + updateDisplay(); +} + + +const YPropertySet & +YBarGraph::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property list Values The numerical value for each segment. + * @property list Labels Text label for each segment ('\n' allowed). + * Use %1 as a placeholder for the current value. + */ + propSet.add( YProperty( YUIProperty_Values, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Labels, YOtherProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YBarGraph::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Values ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Labels ) return false; // Needs special handling + else + { + YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special handling necessary +} + + +YPropertyValue +YBarGraph::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Values ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Labels ) return YPropertyValue( YOtherProperty ); + else + { + return YWidget::getProperty( propertyName ); + } +} + + + + +YBarGraphMultiUpdate::YBarGraphMultiUpdate( YBarGraph * barGraph ) + : _barGraph ( barGraph ) +{ + YUI_CHECK_PTR( barGraph ); + + _barGraph->priv->postponeUpdates = true; +} + + +YBarGraphMultiUpdate::~YBarGraphMultiUpdate() +{ + _barGraph->priv->postponeUpdates = false; + + if ( _barGraph->priv->updatesPending ) + _barGraph->updateDisplay(); +} diff --git a/src/YBarGraph.h b/src/YBarGraph.h new file mode 100644 index 0000000..29f7f26 --- /dev/null +++ b/src/YBarGraph.h @@ -0,0 +1,325 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YBarGraph.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YBarGraph_h +#define YBarGraph_h + +#include "YWidget.h" +#include "YColor.h" + + +class YBarGraphPrivate; +class YBarGraphSegment; + +/** + * A graph showing partitioning of a whole. + * The whole is divided into YBarGraphSegment each of which has + * a relative size, a text color, a background color, and a label. + */ +class YBarGraph : public YWidget +{ + friend class YBarGraphMultiUpdate; + +protected: + /** + * Constructor. + **/ + YBarGraph( YWidget * parent ); + +public: + /** + * Destructor. + **/ + virtual ~YBarGraph(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YBarGraph"; } + + /** + * Add one segment. + * + * If the segment's background and text colors are not explicitly + * specified, the YBarGraph widget will assign them from a list of (at + * least 5 different) color sets. + * + * When adding multiple segments, use a YBarGraphMultiUpdate object for + * improved performance to hold back display updates until all segments are + * added. + **/ + void addSegment( const YBarGraphSegment & segment ); + + /** + * Delete all segments. + **/ + void deleteAllSegments(); + + /** + * Return the current number of segments. + **/ + int segments(); + + /** + * Return the segment with the specified index (from 0 on). + * + * This will throw an exception if there are not this many segments. + **/ + const YBarGraphSegment & segment( int segmentIndex ) const; + + /** + * Set the value of the segment with the specifie index (from 0 on). + * + * This will throw an exception if there are not this many segments. + * + * Note: Use a YBarGraphMultiUpdate object for improved performance + * when doing multiple changes at the same time. + **/ + void setValue( int segmentIndex, int newValue ); + + /** + * Set the label of the segment with the specified index (from 0 on). + * Use %1 as a placeholder for the current value. + * + * This will throw an exception if there are not this many segments. + * + * Note: Use a YBarGraphMultiUpdate object for improved performance + * when doing multiple changes at the same time. + **/ + void setLabel( int segmentIndex, const std::string & newLabel ); + + /** + * Set the background color of the segment with the specified index + * (from 0 on). + * + * This will throw an exception if there are not this many segments + * or if the color is undefined. + **/ + void setSegmentColor( int segmentIndex, const YColor & color ); + + /** + * Set the text color of the segment with the specified index + * (from 0 on). + * + * This will throw an exception if there are not this many segments + * or if the color is undefined. + **/ + void setTextColor( int segmentIndex, const YColor & color ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + +protected: + /** + * Perform a display update after any change to any of the segments. + * + * Derived classes are required to implement this. + **/ + virtual void doUpdate() = 0; + + +private: + /** + * Conditionally perform display update if not currently postponed. + **/ + void updateDisplay(); + + ImplPtr priv; +}; + + + + +/** + * One segment of a YBarGraph. + * It has a relative size, a label, label color and background color. + **/ +class YBarGraphSegment +{ +public: + /** + * Constructor. + * + * 'value' is the initial value of this segment. + * + * 'label' is the label text in the segment. + * Use %1 as a placeholder for the current value. + * + * 'segmentColor' is the background color of this segment. + * + * 'textColor' is the color for the label text. + * + * The YBarGraph widget will automatically assign some default colors (one + * of at least 5 different ones) if none are specified. + **/ + YBarGraphSegment( int value = 0, + const std::string & label = std::string(), + const YColor & segmentColor = YColor(), + const YColor & textColor = YColor() ) + : _value( value ) + , _label( label ) + , _segmentColor( segmentColor ) + , _textColor( textColor ) + {} + + /** + * Return the current value of this segment. + **/ + int value() const { return _value; } + + /** + * Set the value of this segment. + **/ + void setValue( int newValue ) { _value = newValue; } + + /** + * Return the current text label of this segment. + * Any %1 placeholder will be returned as %1 (not expanded). + **/ + std::string label() const { return _label; } + + /** + * Set the text label of this segment. + * Use %1 as a placeholder for the current value. + **/ + void setLabel( const std::string & newLabel ) { _label = newLabel; } + + /** + * Return the segment background color. + **/ + YColor segmentColor() const { return _segmentColor; } + + /** + * Return 'true' if this segment's background color is defined, + * i.e. it has a real RGB value and was not just created with the default + * constructor. + **/ + bool hasSegmentColor() const { return _segmentColor.isDefined(); } + + /** + * Set this segment's background color. + **/ + void setSegmentColor( const YColor & color ) { _segmentColor = color; } + + /** + * Return this segment's text color. + **/ + YColor textColor() const { return _textColor; } + + /** + * Return 'true' if this segment's text color is defined, + * i.e. it has a real RGB value and was not just created with the default + * constructor. + **/ + bool hasTextColor() const { return _textColor.isDefined(); } + + /** + * Set this segment's text color. + **/ + void setTextColor( const YColor & color ) { _textColor = color; } + + +private: + + int _value; + std::string _label; + YColor _segmentColor; + YColor _textColor; +}; + + + +/** + * Helper class for multiple updates to a YBarGraph widget: + * This will hold back display updates until this object goes out of scope. + **/ +class YBarGraphMultiUpdate +{ +public: + /** + * Constructor. + * + * This will make the corresponding YBarGraph widget hold back any + * pending display updates (due to changed values, labels, or colors) until + * this object is destroyed (goes out of scope). + * + * Create objects of this class on the stack (as local variables) and + * simply let them go out of scope. + * + * Example: + * + * { + * YBarGraphMultiUpdate multiUpdate( myBarGraph ); + * myBarGraph->setValue( 0, 42 ); // No display update yet + * myBarGraph->setValue( 1, 84 ); // No display update yet + * myBarGraph->setValue( 2, 21 ); // No display update yet + * + * } // multiUpdate goes out of scope, will trigger display update now + * + **/ + YBarGraphMultiUpdate( YBarGraph * barGraph ); + + /** + * Destructor. + * + * This will trigger display updates of the corresponding YBarGraph widget + * if any are necessary. + **/ + ~YBarGraphMultiUpdate(); + +private: + + YBarGraph * _barGraph; +}; + + +#endif // YBarGraph_h diff --git a/src/YBothDim.h b/src/YBothDim.h new file mode 100644 index 0000000..9c44058 --- /dev/null +++ b/src/YBothDim.h @@ -0,0 +1,99 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YBothDim.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YBothDim_h +#define YBothDim_h + +#include "YTypes.h" +#include "YUIException.h" + + +/** + * Template class for two-dimensional entities, such as + * - width, height + * - x_pos, y_pos + * - hStretchable, vStretchable + * + * Precondition: type T needs to have a default constructor + * (which all simple types like int, long, bool have). + **/ +template class YBothDim +{ +public: + + // Data Members - intentionally public + T vert; + T hor; + + /** + * Constructor with explicit initialization for both values + **/ + YBothDim( T hor, T vert ) + : vert( vert ) + , hor( hor ) + {} + + /** + * Default constructor (calls T default constructor for both values) + **/ + YBothDim() + {} + + /** + * operator[] for alternative access via myVar[ YD_HORIZ ] + * Please note that this returns a non-const reference, so this can be used + * as an lvalue (e.g., in assignments) + **/ + T & operator[]( YUIDimension dim ) + { + switch ( dim ) + { + case YD_HORIZ: return hor; + case YD_VERT: return vert; + default: YUI_THROW( YUIInvalidDimensionException() ); + } + + // never reached (but gcc will complain otherwise) + return hor; + } + + /** + * Same as above for const objects + **/ + const T & operator[]( YUIDimension dim ) const + { + switch ( dim ) + { + case YD_HORIZ: return hor; + case YD_VERT: return vert; + default: YUI_THROW( YUIInvalidDimensionException() ); + } + + // never reached (but gcc will complain otherwise) + return hor; + } +}; + + +#endif // YBothDim_h diff --git a/src/YBuiltinCaller.h b/src/YBuiltinCaller.h new file mode 100644 index 0000000..2949b49 --- /dev/null +++ b/src/YBuiltinCaller.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YBuiltinCaller.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YBuiltinCaller_h +#define YBuiltinCaller_h + + +/** + * Abstract base class for transparently calling a built-in function. + * Derived classes will want to add some methods to store the function to be + * called, arguments to that function and its result and to retrieve the result + * when needed. + * + * See YCPBuiltinCaller.h for an implementation. + **/ +class YBuiltinCaller +{ +protected: + YBuiltinCaller() {} + +public: + virtual ~YBuiltinCaller() {} + + /** + * Call the built-in. This will be called in the UI thread with appropriate + * syncing between the threads. + * + * Derived classes might want to store the result of the call in a member + * variable in this class so it can later be queried. + * + * Derived classes are required to implement this method. + **/ + virtual void call() = 0; +}; + + +#endif // YBuiltinCaller_h diff --git a/src/YBusyIndicator.cc b/src/YBusyIndicator.cc new file mode 100644 index 0000000..ac737d2 --- /dev/null +++ b/src/YBusyIndicator.cc @@ -0,0 +1,160 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YBusyIndicator.cc + + Author: Thomas Goettlicher + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YBusyIndicator.h" + + +struct YBusyIndicatorPrivate +{ + YBusyIndicatorPrivate( const std::string & label, + int timeout , + bool alive ) + : label( label ) + , timeout( timeout ) + , alive (true) + { + } + + std::string label; + int timeout; + bool alive; +}; + + + + +YBusyIndicator::YBusyIndicator( YWidget * parent, + const std::string & label, + int timeout, + bool alive ) + : YWidget( parent ) + , priv( new YBusyIndicatorPrivate( label, timeout, alive ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setStretchable( YD_VERT, false ); +} + + +YBusyIndicator::~YBusyIndicator() +{ + // NOP +} + + +std::string YBusyIndicator::label() +{ + return priv->label; +} + + +void YBusyIndicator::setLabel( const std::string & label ) +{ + priv->label = label; +} + + +int YBusyIndicator::timeout() const +{ + return priv->timeout; +} + + +void YBusyIndicator::setTimeout( int newTimeout ) +{ + if ( newTimeout < 1 ) + newTimeout = 1; + + priv->timeout = newTimeout; +} + + +void YBusyIndicator::setAlive( bool alive ) +{ + priv->alive = alive; +} + +bool YBusyIndicator::alive() const +{ + return priv->alive; +} + +const YPropertySet & +YBusyIndicator::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property integer Timeout timeout in ms until busy indicator changes to stalled state + * @property bool Alive busy indicator is in alive or stalled state + * @property std::string Label caption above the busy indicator + */ + propSet.add( YProperty( YUIProperty_Timeout, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_Alive, YBoolProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YBusyIndicator::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Timeout ) setTimeout( val.integerVal() ); + else if ( propertyName == YUIProperty_Alive ) setAlive( val.boolVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YBusyIndicator::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Timeout ) return YPropertyValue( timeout() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_Alive ) return YPropertyValue( alive() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YBusyIndicator.h b/src/YBusyIndicator.h new file mode 100644 index 0000000..9530fa5 --- /dev/null +++ b/src/YBusyIndicator.h @@ -0,0 +1,140 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YBusyIndicator.h + + Author: Thomas Goettlicher + +/-*/ + +#ifndef YBusyIndicator_h +#define YBusyIndicator_h + +#include "YWidget.h" + +class YBusyIndicatorPrivate; + + +/** + * Indicates that something is in progress and has not frozen yet. + * It has a label and an "indeterminate" progress bar which will be "ticking" + * until a timeout occurs or until it receives an "alive" message. + */ +class YBusyIndicator : public YWidget +{ +protected: + /** + * Constructor. + **/ + YBusyIndicator( YWidget * parent, + const std::string & label, + int timeout = 1000, + bool alive = true ); + +public: + /** + * Destructor. + **/ + virtual ~YBusyIndicator(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YBusyIndicator"; } + + /** + * Get the label (the caption above the progress bar). + **/ + std::string label(); + + /** + * Set the label (the caption above the progress bar). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Return the current timeout in milliseconds. + **/ + int timeout() const; + + /** + * Set the timeout in milliseconds after that the widget shows 'stalled' + * when no new tick is received. + * + * Derived classes should reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setTimeout( int newTimeout ); + + /** + * Return whether busy indicator is alive or in stalled stated. + **/ + bool alive() const; + + + /** + * Send a keep alive message to prevent BusyIndicator from changing + * to 'stalled' state. + * + * Derived classes should reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setAlive( bool newAlive ); + + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + +private: + + ImplPtr priv; +}; + + +#endif // YBusyIndicator_h diff --git a/src/YButtonBox.cc b/src/YButtonBox.cc new file mode 100644 index 0000000..8fe97b5 --- /dev/null +++ b/src/YButtonBox.cc @@ -0,0 +1,650 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YButtonBox.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include // max() +#include +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YButtonBox.h" +#include "YPushButton.h" +#include "YUI.h" +#include "YApplication.h" + +using std::max; + + +YButtonBoxLayoutPolicy YButtonBox::_layoutPolicy = kdeLayoutPolicy(); +YButtonBoxMargins YButtonBox::_defaultMargins; + + +struct YButtonBoxPrivate +{ + /** + * Constructor + **/ + YButtonBoxPrivate() + : sanityCheckRelaxed( false ) + , margins( YButtonBox::_defaultMargins ) + {} + + // + // Data members + // + + bool sanityCheckRelaxed; + YButtonBoxMargins margins; +}; + + + + +YButtonBox::YButtonBox( YWidget * parent ) + : YWidget( parent ) + , priv( new YButtonBoxPrivate() ) +{ + YUI_CHECK_NEW( priv ); + setChildrenManager( new YWidgetChildrenManager( this ) ); +} + + +YButtonBox::~YButtonBox() +{ + // NOP +} + + +void +YButtonBox::setLayoutPolicy( const YButtonBoxLayoutPolicy & layoutPolicy ) +{ + _layoutPolicy = layoutPolicy; +} + + +YButtonBoxLayoutPolicy +YButtonBox::layoutPolicy() +{ + return _layoutPolicy; +} + + +YButtonBoxLayoutPolicy +YButtonBox::kdeLayoutPolicy() +{ + YButtonBoxLayoutPolicy policy; + + policy.buttonOrder = YKDEButtonOrder; + policy.equalSizeButtons = false; + policy.alignment[ YD_HORIZ ] = YAlignCenter; + policy.alignment[ YD_VERT ] = YAlignBegin; // Align top + + return policy; +} + + +YButtonBoxLayoutPolicy +YButtonBox::gnomeLayoutPolicy() +{ + YButtonBoxLayoutPolicy policy; + + policy.buttonOrder = YGnomeButtonOrder; + policy.equalSizeButtons = true; + policy.alignment[ YD_HORIZ ] = YAlignEnd; // Align right + policy.alignment[ YD_VERT ] = YAlignBegin; // Align top + policy.addExcessSpaceToHelpButtonExtraMargin = true; + + return policy; +} + + +void +YButtonBox::setDefaultMargins( const YButtonBoxMargins & margins ) +{ + _defaultMargins = margins; +} + + +YButtonBoxMargins +YButtonBox::defaultMargins() +{ + return _defaultMargins; +} + + +void +YButtonBox::setMargins( const YButtonBoxMargins & margins ) +{ + priv->margins = margins; +} + + +YButtonBoxMargins +YButtonBox::margins() const +{ + return priv->margins; +} + + +void +YButtonBox::setSize( int newWidth, int newHeight ) +{ + sanityCheck(); + doLayout( newWidth, newHeight ); +} + + +void +YButtonBox::doLayout( int width, int height ) +{ + std::vector buttons = buttonsByButtonOrder(); + + if ( buttons.empty() ) + return; + + YPushButton * helpButton = findButton( YHelpButton ); + + int prefWidth = preferredWidth(); + int prefHeight = preferredHeight(); + YButtonBoxMargins margins = priv->margins; + bool equalSizeButtons = _layoutPolicy.equalSizeButtons; + + + // + // Horizontal layout + // + + if ( width < prefWidth ) // Not enough horizontal space + { + if ( equalSizeButtons ) + { + int buttonWidthWithoutMargins = maxChildSize( YD_HORIZ ) * buttons.size(); + + if ( width < buttonWidthWithoutMargins ) + { + // The missing width can't be compensated by reducing margins and spacings. + // Try not enforcing the same width: + // + // If one button is very much larger than most others, that one + // button will greatly distort the overall layout. If we simply cut + // some pixels off every button, for sure that one very large + // button will become unreadable. So let's try first with buttons + // getting just the size they really need. + // + // Of course, we might still have cut some pixels off all buttons + // if that also is too wide, but in that case we can't do very much + // anyway. + + equalSizeButtons = false; + prefWidth = preferredWidth( equalSizeButtons ); + } + } + } + + int widthLoss = 0; + + if ( width < prefWidth ) // Not enough horizontal space + { + // Try reducing margins + + int missing = prefWidth - width; + + if ( missing <= margins.left + margins.right ) + { + margins.left -= missing / 2; + margins.right -= missing / 2; + missing = 0; + } + else + { + missing -= margins.left; + missing -= margins.right; + margins.left = 0; + margins.right = 0; + } + + if ( missing > 0 && buttons.size() > 1 ) + { + // Try reducing spacing + + int totalSpacing = ( buttons.size() - 1 ) * margins.spacing; + + if ( missing <= totalSpacing ) + { + totalSpacing -= missing; + margins.spacing = totalSpacing / ( buttons.size() - 1 ); + missing = 0; + } + else + { + missing -= totalSpacing; + margins.spacing = 0; + } + } + + if ( missing > 0 && helpButton ) + { + // Try reducing help button extra spacing + + if ( missing <= margins.helpButtonExtraSpacing ) + { + margins.helpButtonExtraSpacing -= missing; + missing = 0; + } + else + { + missing -= margins.helpButtonExtraSpacing; + margins.helpButtonExtraSpacing = 0; + } + } + + + // Distribute missing width among all buttons + + if ( missing > 0 ) + widthLoss = missing / buttons.size(); + } + + if ( width > prefWidth ) // Excess horizontal space + { + int excessWidth = width - prefWidth; + + if ( _layoutPolicy.addExcessSpaceToHelpButtonExtraMargin && helpButton ) + { + margins.helpButtonExtraSpacing += excessWidth; + } + else + { + switch ( _layoutPolicy.alignment[ YD_HORIZ ] ) + { + case YAlignCenter: + margins.left += excessWidth / 2; + margins.right += excessWidth / 2; + break; + + case YAlignBegin: + case YAlignUnchanged: + margins.right += excessWidth; + break; + + case YAlignEnd: + margins.left += excessWidth; + break; + } + } + } + + + // + // Vertical layout + // + + int buttonHeight = maxChildSize( YD_VERT ); + + if ( height < prefHeight ) // Not enough vertical space + { + // Reduce margins + + int missing = prefHeight - height; + + if ( missing < margins.top + margins.bottom ) + { + margins.top -= missing / 2; + margins.bottom -= missing / 2; + } + else + { + margins.top = 0; + margins.bottom = 0; + } + } + + if ( height < buttonHeight ) + { + buttonHeight = height; + } + + int y_pos = margins.top; + + if ( height > prefHeight ) // Excess vertical space + { + // Distribute excess vertical space + + int excessHeight = height - buttonHeight; + excessHeight -= margins.top; + excessHeight -= margins.bottom; + + switch ( _layoutPolicy.alignment[ YD_VERT ] ) + { + case YAlignBegin: // Align top + case YAlignUnchanged: + break; + + case YAlignCenter: + y_pos += excessHeight / 2; + break; + + case YAlignEnd: // Align bottom + y_pos += excessHeight; + break; + } + } + + + // + // Set child widget positions and sizes from left to right + // + + int x_pos = margins.left; + int buttonWidth = 0; + + if ( equalSizeButtons ) + { + buttonWidth = maxChildSize( YD_HORIZ ); + buttonWidth -= widthLoss; + } + + bool reverseLayout = YUI::app()->reverseLayout(); + + for ( std::vector::iterator it = buttons.begin(); + it != buttons.end(); + ++it ) + { + YPushButton * button = *it; + + // Extra spacing left of [Help] button + // (Only if this isn't the first button) + + if ( button == helpButton && button != buttons.front() ) + x_pos += margins.helpButtonExtraSpacing; + + if ( ! equalSizeButtons ) + { + buttonWidth = button->preferredWidth(); + buttonWidth -= widthLoss; + } + + button->setSize( buttonWidth, buttonHeight ); + + if ( reverseLayout ) + moveChild( button, width - x_pos - buttonWidth, y_pos ); + else + moveChild( button, x_pos, y_pos ); + + x_pos += buttonWidth; + x_pos += margins.spacing; + + + // Extra spacing right of [Help] button + + if ( button == helpButton ) + x_pos += margins.helpButtonExtraSpacing; + } +} + + +std::vector +YButtonBox::buttonsByButtonOrder() +{ + std::vector specialButtons( YMaxButtonRole, (YPushButton *) 0 ); + std::vector customButtons; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YPushButton * button = dynamic_cast (*it); + + if ( ! button ) + YUI_THROW( YUIInvalidChildException( this, *it ) ); + + switch ( button->role() ) + { + case YOKButton: + case YCancelButton: + case YApplyButton: + case YHelpButton: + case YRelNotesButton: + + if ( specialButtons[ button->role() ] ) // Only one of each of those is allowed + { + std::string msg = "Multiple buttons with that role ["; + msg += button->debugLabel(); + msg += "]"; + YUI_THROW( YUIButtonRoleMismatchException( msg ) ); + } + else + { + specialButtons[ button->role() ] = button; + } + break; + + case YCustomButton: + customButtons.push_back( button ); + break; + + case YMaxButtonRole: + YUI_THROW( YUIButtonRoleMismatchException( "Invalid button role" ) ); + break; + } + } + + std::vector buttons; + + if ( _layoutPolicy.buttonOrder == YKDEButtonOrder ) + { + if ( specialButtons[ YOKButton ] ) buttons.push_back( specialButtons[ YOKButton ] ); + if ( specialButtons[ YApplyButton ] ) buttons.push_back( specialButtons[ YApplyButton ] ); + if ( specialButtons[ YCancelButton ] ) buttons.push_back( specialButtons[ YCancelButton ] ); + + buttons.insert( buttons.end(), customButtons.begin(), customButtons.end() ); + + if ( specialButtons[ YHelpButton ] ) buttons.push_back( specialButtons[ YHelpButton ] ); + } + else // YGnomeButtonOrder + { + if ( specialButtons[ YHelpButton ] ) buttons.push_back( specialButtons[ YHelpButton ] ); + + buttons.insert( buttons.end(), customButtons.begin(), customButtons.end() ); + + if ( specialButtons[ YApplyButton ] ) buttons.push_back( specialButtons[ YApplyButton ] ); + if ( specialButtons[ YCancelButton ] ) buttons.push_back( specialButtons[ YCancelButton ] ); + if ( specialButtons[ YOKButton ] ) buttons.push_back( specialButtons[ YOKButton ] ); + } + + return buttons; +} + + + +int +YButtonBox::preferredWidth( bool equalSizeButtons ) +{ + if ( childrenCount() < 1 ) + return 0; + + int width = ( childrenCount() - 1 ) * priv->margins.spacing; + + if ( equalSizeButtons ) + width += maxChildSize( YD_HORIZ ) * childrenCount(); + else + width += totalChildrenWidth(); + + width += priv->margins.left; + width += priv->margins.right; + + if ( priv->margins.helpButtonExtraSpacing ) + { + if ( findButton( YHelpButton ) ) + width += priv->margins.helpButtonExtraSpacing; + } + + return width; +} + + +int +YButtonBox::preferredWidth() +{ + return preferredWidth( _layoutPolicy.equalSizeButtons ); +} + + +int +YButtonBox::preferredHeight() +{ + int height = maxChildSize( YD_VERT ); + height += priv->margins.top; + height += priv->margins.bottom; + + return height; +} + + +int +YButtonBox::maxChildSize( YUIDimension dim ) const +{ + int maxSize = 0; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + maxSize = max( maxSize, (*it)->preferredSize( dim ) ); + } + + return maxSize; +} + + +int +YButtonBox::totalChildrenWidth() const +{ + int totalWidth = 0; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + totalWidth += (*it)->preferredWidth(); + } + + return totalWidth; +} + + +bool +YButtonBox::stretchable( YUIDimension dimension ) const +{ + switch ( dimension ) + { + case YD_HORIZ: return true; + case YD_VERT : return false; + + default: + YUI_THROW( YUIInvalidDimensionException() ); + return 0; + } +} + + +YPushButton * +YButtonBox::findButton( YButtonRole role ) +{ + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YPushButton * button = dynamic_cast (*it); + + if ( button && button->role() == role ) + return button; + } + + return 0; +} + + +void +YButtonBox::setSanityCheckRelaxed( bool relaxed ) +{ + priv->sanityCheckRelaxed = relaxed; +} + + +bool +YButtonBox::sanityCheckRelaxed() const +{ + return priv->sanityCheckRelaxed; +} + + +void +YButtonBox::sanityCheck() +{ + YPushButton * okButton = 0; + YPushButton * cancelButton = 0; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YPushButton * button = dynamic_cast (*it); + + if ( ! button ) + YUI_THROW( YUIInvalidChildException( this, *it ) ); + + switch ( button->role() ) + { + case YOKButton: + + if ( okButton ) + YUI_THROW( YUIButtonRoleMismatchException( "Multiple buttons with role [OK]" ) ); + else + okButton = button; + break; + + + case YCancelButton: + + if ( cancelButton ) + YUI_THROW( YUIButtonRoleMismatchException( "Multiple buttons with role [Cancel]" ) ); + else + cancelButton = button; + break; + + + default: + break; + } + } + + if ( childrenCount() > 1 && ! sanityCheckRelaxed() ) + { + if ( ! okButton || ! cancelButton ) + YUI_THROW( YUIButtonRoleMismatchException( "Button role mismatch: Must have both [OK] and [Cancel] roles" ) ); + } +} diff --git a/src/YButtonBox.h b/src/YButtonBox.h new file mode 100644 index 0000000..84f8dbb --- /dev/null +++ b/src/YButtonBox.h @@ -0,0 +1,395 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YButtonBox.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YButtonBox_h +#define YButtonBox_h + +#include + +#include "YWidget.h" +#include "YPushButton.h" + +class YButtonBoxPrivate; +class YPushButton; + + +/** + * Helper class: Layout policy for YButtonBox widgets. + * This is used in the default YButtonBox::doLayout() method. + **/ +struct YButtonBoxLayoutPolicy +{ + YButtonBoxLayoutPolicy() + : buttonOrder( YKDEButtonOrder ) + , equalSizeButtons( false ) + , addExcessSpaceToHelpButtonExtraMargin( false ) + { + alignment[ YD_HORIZ ] = YAlignCenter; + alignment[ YD_VERT ] = YAlignBegin; // Align top + } + + YButtonOrder buttonOrder; // YKDEButtonOrder / YGnomeButtonOrder + bool equalSizeButtons; // Make all buttons the same size? + bool addExcessSpaceToHelpButtonExtraMargin; + + // Alignment for the YButtonBox itself + YAlignmentType alignment[ YUIAllDimensions ]; +}; + + +/** + * Helper class: Margins for YButtonBox widgets. + * All sizes are in UI-dependent units, i.e. in pixels. + **/ +struct YButtonBoxMargins +{ + YButtonBoxMargins() + : left( 0 ) + , right( 0 ) + , top( 0 ) + , bottom( 0 ) + , spacing( 0 ) + , helpButtonExtraSpacing( 0 ) + {} + + int left; // Left of the leftmost button + int right; // Right of the rightmost button + int top; // Above the hightest button + int bottom; // Below the hightest button + + int spacing; // Between buttons + int helpButtonExtraSpacing; // Between [Help] and the next button +}; // (additionally to "spacing"!) + + +/** + * Container widget for dialog buttons that abstracts the button order + * depending on the desktop environment. + * + * KDE and Windows arrange dialog buttons like this: + * + * [OK] [Apply] [Cancel] [Custom1] [Custom2] ... [Help] + * + * [Continue] [Cancel] + * + * [Yes] [No] + * + * + * GNOME and MacOS arrange them like this: + * + * [Help] [Custom1] [Custom2] ... [Apply] [Cancel] [OK] + * + * [Cancel] [Continue] + * + * [No] [Yes] + * + * + * This class provides the abstraction to use whatever layout is more + * appropriate in the current environment. The application creates the buttons + * as child widgets of a YButtonBox (rather than a YHBox) and leaves the button + * order to the YButtonBox. + * + * Each of the standard buttons ([OK], [Apply], [Cancel], [Help]) needs to have + * a button role properly assigned. + * + * If set up properly (see YApplication::setDefaultFunctionKey()), known button + * labels will be assigned an appropriate role: + * + * [OK] F10 + * [Continue] -> [OK] F10 + * [Yes] -> [OK] F10 + * [Accept] -> [OK] F10 + * [Next] -> [OK] F10 + * + * [Cancel] F9 + * [No] -> [Cancel] F9 + * + * [Help] F1 + * + * Buttons with nonstandard labels that act in such a role need to be + * explicitly assigned that role: + * + * [Print ] [Cancel] [Help] + * [Delete] [Cancel] [Help] + * + * Those [Print] or [Delete] buttons act as [OK] buttons (the "yes, do it" + * action of that dialog). Call YPushButton::setButtonRole( YOkButton ) + * explicitly for them. + * + * + * YButtonBox widgets only accept YPushButton child widgets. Otherwise an + * exception is thrown. + * + * If there is more than one button, one of the child buttons needs to have the + * [OK] role, and another needs to have the [Cancel] role. Otherwise an + * exception is thrown. + **/ +class YButtonBox : public YWidget +{ + friend class YButtonBoxPrivate; + +protected: + /** + * Constructor. + **/ + YButtonBox( YWidget * parent ); + +public: + + /** + * Destructor. + **/ + virtual ~YButtonBox(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YButtonBox"; } + + /** + * Set the button policy for all future YButtonBox widgets: + * Button order, alignment if there is any excess space, whether or not to + * give all buttons the same size. + * + * You might want to use one of the predefined static methods: + * YButtonBox::kdeLayoutPolicy(), YButtonBox::gnomeLayoutPolicy(). + * + * The default doLayout() method uses those values. + * + * Notice that there is intentionally no way to set this differently for + * each individual YButtonBox: This would defeat the purpose of consistency + * (with the desktop environment this application is running in), which is + * the reason for having this widget class. + **/ + static void setLayoutPolicy( const YButtonBoxLayoutPolicy & layoutPolicy ); + + /** + * Return the layout policy. + **/ + static YButtonBoxLayoutPolicy layoutPolicy(); + + /** + * Predefined layout policy for KDE-like behaviour. + **/ + static YButtonBoxLayoutPolicy kdeLayoutPolicy(); + + /** + * Predefined layout policy for GNOME-like behaviour. + **/ + static YButtonBoxLayoutPolicy gnomeLayoutPolicy(); + + /** + * Set the default margins for all future YButtonBox widgets. + **/ + static void setDefaultMargins( const YButtonBoxMargins & margins ); + + /** + * Return the default margins for all future YButtonBox widgets. + **/ + static YButtonBoxMargins defaultMargins(); + + /** + * Set the margins for this YButtonBox. + * + * Derived classes are free to reimplement this, but they should call this + * base class method in the new method. + **/ + virtual void setMargins( const YButtonBoxMargins & margins ); + + /** + * Return the margins of this YButtonBox. + * + * Notice that those are only the desired margins; if there is not enough + * space, margins and spacings will be reduced before buttons are cut off. + **/ + YButtonBoxMargins margins() const; + + /** + * Lay out the button box and its children (its buttons). This is where the + * button order is implemented. + * + * This method is called by the default setSize() method. It uses + * YButtonBox::layoutPolicy() and the specified margins (defaultMargins + * unless changed with setMargins() ). It moves the buttons to their + * position with moveChild(). + * + * This all should work reasonably in all cases (Qt-UI with KDE button + * order, Gtk-UI with Gnome button order, NCurses-UI with KDE button + * order). + * + * Still, derived classes can reimplement this. It does not make very much + * sense to call this default method in a new implementation. + **/ + virtual void doLayout( int width, int height ); + + /** + * Search the child widgets for the first button with the specified role. + * Return the button or 0 if there is no button with that role. + **/ + YPushButton * findButton( YButtonRole role ); + + /** + * Sanity check: Check if all child widgets have the correct widget class + * and if the button roles are assigned correctly. + * + * A YButtonBox with more than one button is required to have one YOKButton + * and ony YCancelButton. Neither button role may be assigned more than + * once. + * + * This method may throw exceptions: + * - YUIButtonRoleMismatchException + * - YUIInvalidChildException (wrong widget class) + * + * This cannot be done as child widgets are inserted since this is done + * from the child widgets' constructors, so virtual methods or dynamic_cast + * don't work at that point. + * + * This is called in the default setSize() method (just before doLayout()), + * so any of the above errors are caught only at that time. Applications + * are free to call this before that time to make error handling more + * transparent. + **/ + void sanityCheck(); + + /** + * Relax the sanity check done in sanityCheck(): Do not enforce that there + * has to be a YOKButton and a YCancelButton if there is more than one + * button. + * + * In very rare cases, it might be neccessary to have a less stringent + * sanity check: There are some very few legitimate cases for having a + * YButtonBox with multiple buttons, yet without a YCancelButton. + * + * Examples: + * + * ...message... + * + * [OK] [Stop] + * + * ...message... + * [OK] [Details] + * + * In those cases, it makes sense to relax the sanity check. + **/ + void setSanityCheckRelaxed( bool relax = true ); + + /** + * Return 'true' if sanity checks are currently relaxed, 'false' if not. + **/ + bool sanityCheckRelaxed() const; + + /** + * Preferred width of the widget. + * + * Reimplemented from YWidget. This default method returns the sum of + * the the widths of all child widgets plus the left and right margins plus + * the spacings. + * + * Derived classes can reimplement this method. It does not make very much + * sense to call this base class method in a new implementation. + **/ + virtual int preferredWidth(); + + /** + * Preferred height of the widget. + * + * Reimplemented from YWidget. This default method returns the height of + * the highest child plus the top and bottom margins. + * + * Derived classes can reimplement this method. It does not make very much + * sense to call this base class method in a new implementation. + **/ + virtual int preferredHeight(); + + /** + * Sets the size of the YButtonBox. + * + * Derived classes can reimplement this, but this base class method should + * be called in the reimplemented function. + * + * Reimplemented from YWidget. + **/ + virtual void setSize( int newWidth, int newHeight ); + + /** + * Returns the stretchability of the YButtonBox. YButtonBox widgets are + * horizontally stretchable by default. How any excess space is used is + * specified in the layout policy. + * + * Reimplemented from YWidget. + **/ + virtual bool stretchable( YUIDimension dimension ) const; + + +protected: + + /** + * Return the button children sorted (left to right) by the current button + * order (from the layout policy). + * + * This default implementation handles KDE and Gnome button orders. It is + * used in the default doLayout() method. + * + * This may throw exceptions if there are non-button children or if there + * are multiple buttons with any of the standard button roles (except + * YCustomButton, of course). + **/ + virtual std::vector buttonsByButtonOrder(); + + /** + * Return the (preferred) size of the biggest child widget in the specified + * dimension. + **/ + int maxChildSize( YUIDimension dim ) const; + + /** + * Return the sum of the (preferred) widths of all child widgets. + **/ + int totalChildrenWidth() const; + + /** + * Move a child to a new position. This is used in doLayout(). + * + * Derived classes are required to implement this. + **/ + virtual void moveChild( YWidget * child, int newX, int newY ) = 0; + + /** + * Calculate the preferred with with or without trying to enforce buttons + * of equal size. + **/ + int preferredWidth( bool equalSizeButtons ); + + +private: + + ImplPtr priv; + + static YButtonBoxLayoutPolicy _layoutPolicy; + static YButtonBoxMargins _defaultMargins; +}; + + +#endif // YButtonBox_h diff --git a/src/YCheckBox.cc b/src/YCheckBox.cc new file mode 100644 index 0000000..c423b81 --- /dev/null +++ b/src/YCheckBox.cc @@ -0,0 +1,131 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YCheckBox.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YCheckBox.h" + + +struct YCheckBoxPrivate +{ + YCheckBoxPrivate( const std::string & label ) + : label( label ) + , useBoldFont( false ) + {} + + std::string label; + bool useBoldFont; +}; + + +YCheckBox::YCheckBox( YWidget * parent, const std::string & label ) + : YWidget( parent ) + , priv( new YCheckBoxPrivate( label ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YCheckBox::~YCheckBox() +{ + // NOP +} + + +void YCheckBox::setLabel( const std::string & newLabel ) +{ + priv->label = newLabel; +} + + +std::string YCheckBox::label() const +{ + return priv->label; +} + + +bool YCheckBox::useBoldFont() const +{ + return priv->useBoldFont; +} + + +void YCheckBox::setUseBoldFont( bool bold ) +{ + priv->useBoldFont = bold; +} + + +const YPropertySet & +YCheckBox::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property boolean Value the on/off state; nil for "don't care" (tristate) + * @property std::string Label the text on the CheckBox + */ + + propSet.add( YProperty( YUIProperty_Value, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YCheckBox::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) return false; // need special processing + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YCheckBox::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YCheckBox.h b/src/YCheckBox.h new file mode 100644 index 0000000..793cc77 --- /dev/null +++ b/src/YCheckBox.h @@ -0,0 +1,206 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YCheckBox.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YCheckBox_h +#define YCheckBox_h + +#include + +#include "YWidget.h" +#include "ImplPtr.h" + +class YCheckBoxPrivate; + +enum YCheckBoxState +{ + YCheckBox_dont_care = -1, // tristate + YCheckBox_off = 0, + YCheckBox_on = 1 +}; + +/** + * A tri-state check box. It can be toggled between ON and OFF by the user + * and additionally set to a DONT-CARE value programatically. + **/ +class YCheckBox : public YWidget +{ +protected: + /** + * Constructor. + **/ + YCheckBox( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YCheckBox(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YCheckBox"; } + + + /** + * Get the current value: + * + * YCheckBox_on CheckBox is checked + * YCheckBox_off CheckBox is unchecked + * + * YCheckBox_dont_care tri-state: CheckBox is greyed out, + * neither checked nor unchecked + * + * The user cannot set YCheckBox_dont_care directly. This status is always + * only set from the outside, usually because a setting cannot be clearly + * determined. For example, a checkbox + * + * [ ] Read only + * + * would be set to "don't care" (by the application, not directly by the + * user) when it is to display the read-only state of a group of files + * where some are read-only and some are writeable. + * + * Derived classes are required to implement this function. + * (Intentionally not const) + **/ + virtual YCheckBoxState value() = 0; + + /** + * Set the CheckBox value (on/off/don't care). + * + * Derived classes are required to implement this. + **/ + virtual void setValue( YCheckBoxState state ) = 0; + + /** + * Simplified access to value(): Return 'true' if the CheckBox is checked. + **/ + bool isChecked() { return value() == YCheckBox_on; } + + /** + * Simplified access to setValue(): Check of uncheck the CheckBox. + **/ + void setChecked( bool checked = true ) + { setValue( checked ? YCheckBox_on : YCheckBox_off ); } + + /** + * Simplified access to tri-state ("don't care"). + **/ + bool dontCare() { return value() == YCheckBox_dont_care; } + + /** + * Simplified access to setting tri-state ("don't care"). + **/ + void setDontCare() { setValue( YCheckBox_dont_care ); } + + /** + * Get the label (the text on the CheckBox). + **/ + std::string label() const; + + /** + * Set the label (the text on the CheckBox). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Returns 'true' if a bold font should be used. + **/ + bool useBoldFont() const; + + /** + * Indicate whether or not a bold font should be used. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setUseBoldFont( bool bold = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property set upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + +private: + + ImplPtr priv; +}; + + +#endif // YCheckBox_h diff --git a/src/YCheckBoxFrame.cc b/src/YCheckBoxFrame.cc new file mode 100644 index 0000000..84332e9 --- /dev/null +++ b/src/YCheckBoxFrame.cc @@ -0,0 +1,159 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YCheckBoxFrame.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YCheckBoxFrame.h" + + +struct YCheckBoxFramePrivate +{ + YCheckBoxFramePrivate( const std::string & label ) + : label( label ) + , autoEnable( true ) + , invertAutoEnable( false ) + {} + + std::string label; + bool autoEnable; + bool invertAutoEnable; +}; + + + + +YCheckBoxFrame::YCheckBoxFrame( YWidget * parent, + const std::string & label, + bool isChecked ) + : YSingleChildContainerWidget( parent ) + , priv( new YCheckBoxFramePrivate( label ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YCheckBoxFrame::~YCheckBoxFrame() +{ + // NOP +} + + +std::string YCheckBoxFrame::label() const +{ + return priv->label; +} + +void YCheckBoxFrame::setLabel( const std::string & label ) +{ + priv->label = label; +} + +bool YCheckBoxFrame::autoEnable() const +{ + return priv->autoEnable; +} + +void YCheckBoxFrame::setAutoEnable( bool autoEnable ) +{ + // yuiDebug() << "Auto enable: " << boolalpha << autoEnable << std::endl; + priv->autoEnable = autoEnable; +} + +bool YCheckBoxFrame::invertAutoEnable() const +{ + return priv->invertAutoEnable; +} + +void YCheckBoxFrame::setInvertAutoEnable( bool invertAutoEnable ) +{ + // yuiDebug() << "Invert auto enable: ", boolalpha << invertAutoEnable << std::endl; + priv->invertAutoEnable = invertAutoEnable; +} + + +void YCheckBoxFrame::handleChildrenEnablement( bool enabled ) +{ + if ( autoEnable() ) + { + if ( invertAutoEnable() ) + enabled = ! enabled; + + yuiDebug() << ( enabled ? "Enabling" : "Disabling" ) << " child widgets of " << this << std::endl; + setChildrenEnabled( enabled ); + } +} + + +const YPropertySet & +YCheckBoxFrame::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property boolean Value the on/off state of the CheckBoxFrame's check box + * @property std::string Label the text on the frame + */ + + propSet.add( YProperty( YUIProperty_Value, YBoolProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YCheckBoxFrame::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.boolVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YCheckBoxFrame::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YCheckBoxFrame.h b/src/YCheckBoxFrame.h new file mode 100644 index 0000000..243f1a0 --- /dev/null +++ b/src/YCheckBoxFrame.h @@ -0,0 +1,188 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YCheckBoxFrame.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YCheckBoxFrame_h +#define YCheckBoxFrame_h + +#include +#include "YSingleChildContainerWidget.h" +#include "ImplPtr.h" + +class YCheckBoxFramePrivate; + + +/** + * A frame with a check-box, may auto-disable frame contents based on the check. + * See #setAutoEnable, #invertAutoEnable. + **/ +class YCheckBoxFrame : public YSingleChildContainerWidget +{ +public: + /** + * Constructor. + **/ + YCheckBoxFrame( YWidget * parent, + const std::string & label, + bool checked ); + + /** + * Destructor. + **/ + virtual ~YCheckBoxFrame(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YCheckBoxFrame"; } + + /** + * Return the label text on the CheckBoxFrame. + **/ + std::string label() const; + + /** + * Change the label text on the CheckBoxFrame. + * + * Derived classes should overload this, but call this base class function + * in the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Check or uncheck the CheckBoxFrame's check box. + * + * Derived classes are required to implement this. + **/ + virtual void setValue( bool isChecked ) = 0; + + /** + * Get the status of the CheckBoxFrame's check box. + * + * Derived classes are required to implement this. + **/ + virtual bool value() = 0; + + /** + * Handle children enabling/disabling automatically based on the + * CheckBoxFrame's check box? + **/ + bool autoEnable() const; + + /** + * Change autoEnabled flag. + * + * Derived classes are free to overload this, but they should call this + * base class function in the overloaded function. + **/ + virtual void setAutoEnable( bool autoEnable ); + + /** + * Invert the meaning of the CheckBoxFrame's check box, i.e., disable child + * widgets when checked? + **/ + bool invertAutoEnable() const; + + /** + * Change invertAutonEnable flag. + * + * Derived classes are free to overload this, but they should call this + * base class function in the overloaded function. + **/ + virtual void setInvertAutoEnable( bool invertAutoEnable ); + + /** + * Handle enabling/disabling of child widgets based on 'isChecked' (the + * current status of the check box) and autoEnable() and + * invertAutoEnable(). + * + * Derived classes should call this when the check box status changes + * rather than try to handle it on their level. + * + * This method also needs to be called after new child widgets are added to + * establish the initial enabled or disabled state of the child widgets. + **/ + void handleChildrenEnablement( bool isChecked ); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property set upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + +private: + + ImplPtr priv; +}; + + +#endif // YCheckBoxFrame_h diff --git a/src/YChildrenManager.h b/src/YChildrenManager.h new file mode 100644 index 0000000..a280160 --- /dev/null +++ b/src/YChildrenManager.h @@ -0,0 +1,237 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YChildrenManager.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YChildrenManager_h +#define YChildrenManager_h + +#include +#include +#include "YUIException.h" + + +/** + * Abstract base template class for children management, such as child + * widgets. + **/ +template class YChildrenManager +{ +public: + + /** + * Constructor. + * + * 'containerParent' is the class whose children are managed. + **/ + YChildrenManager( T * containerParent ) + : _container( containerParent ) + {} + + /** + * Destructor. + **/ + virtual ~YChildrenManager() {} + + + typedef std::list ChildrenList; + + /** + * Check if there are any children. + **/ + bool hasChildren() const { return ! empty(); } + + /** + * Check if the children list is empty, i.e. if there are no children. + **/ + bool empty() const { return _children.empty(); } + + /** + * Returns the number of children. + **/ + int count() const { return _children.size(); } + + /** + * Return an iterator that points to the first child. + **/ + typename ChildrenList::iterator begin() + { return _children.begin(); } + + /** + * Return an iterator that points after the last child. + **/ + typename ChildrenList::iterator end() + { return _children.end(); } + + /** + * Return an iterator that points to the first child. + **/ + typename ChildrenList::const_iterator begin() const + { return _children.begin(); } + + /** + * Return an iterator that points after the last child. + **/ + typename ChildrenList::const_iterator end() const + { return _children.end(); } + + /** + * Return a reverse iterator that points to the last child. + **/ + typename ChildrenList::const_reverse_iterator rbegin() const + { return _children.rbegin(); } + + /** + * Return a reverse iterator that points before the first child. + **/ + typename ChildrenList::const_reverse_iterator rend() const + { return _children.rend(); } + + /** + * Returns the first child or 0 if there is none. + * Useful mostly for children managers that handle only one child. + **/ + T * firstChild() + { return _children.empty() ? (T *) 0 : _children.front(); } + + /** + * Returns the last child or 0 if there is none. + **/ + T * lastChild() + { return _children.empty() ? (T *) 0 : _children.back(); } + + /** + * Add a new child. + * + * This may throw exceptions if more children are added than the class + * whose children are handled (the associated widget) can handle. + **/ + virtual void add( T * child ) + { _children.push_back( child ); } + + /** + * Remove a child. This only removes the child from the children manager's + * list; it does not delete it. + **/ + virtual void remove( T * child ) + { _children.remove( child ); } + + /** + * Remove all children. This only removes the children from the children + * manager's list; it does not delete them. + **/ + virtual void clear() + { _children.clear(); } + + /** + * Check if the children list contains the specified child. + * Returns 'true' if the children list contains the child, + * 'false' otherwise. + **/ + bool contains( T * child ) const + { + return ( find( _children.begin(), _children.end(), child ) + != _children.end() ); + } + + /** + * Returns the associated container, i.e. the object whose children are + * handled here. + **/ + T * container() const { return _container; } + +protected: + + T * _container; + ChildrenList _children; +}; + + +/** + * Children manager that can handle one single child (rejecting any more). + * Useful for YAlignment, YFrame etc. + **/ +template class YSingleChildManager: public YChildrenManager +{ +public: + + YSingleChildManager( T * containerParent ) + : YChildrenManager( containerParent ) + {} + + /** + * Add a new child. + * + * Reimplemented from YChildrenManager. + * + * This will throw a YUITooManyChildrenException if there already is a + * child. + **/ + virtual void add( T * child ) + { + if ( this->empty() ) + this->_children.push_back( child ); + else + YUI_THROW( YUITooManyChildrenException( this->container() ) ); + } + + /** + * Replace the previous child (if any) with a new one. + **/ + void replace( T * newChild ) + { + this->_children.clear(); + this->_children.push_back( newChild ); + } +}; + + +/** + * Children manager that rejects all children. + * + * Useful for widget classes that can't handle children such as YPushButton, + * YSelectionBox etc. + **/ +template class YChildrenRejector: public YChildrenManager +{ +public: + /** + * Constructor. + **/ + YChildrenRejector( T * containerParent ) + : YChildrenManager( containerParent ) + {} + + /** + * Add a new child. + * + * Reimplemented from YChildrenManager. + * + * Since this class is designed to reject children, this always throws a + * YUITooManyChildrenException. + **/ + virtual void add( T * child ) + { YUI_THROW( YUITooManyChildrenException( this->container() ) ); } +}; + + +#endif // YChildrenManager_h diff --git a/src/YColor.h b/src/YColor.h new file mode 100644 index 0000000..4ea89f9 --- /dev/null +++ b/src/YColor.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YColor.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YColor_h +#define YColor_h + +typedef unsigned char uchar; + + +/** + * Helper class to define an RGB color. + **/ +class YColor +{ +public: + /** + * Constructor. + **/ + YColor( uchar red, uchar green, uchar blue ) + : _red ( red ) + , _green( green ) + , _blue ( blue ) + , _undef( false ) + {} + + /** + * Default constructor: Create "undefined" color. + **/ + YColor() + : _red( 0 ), _green( 0 ), _blue( 0 ) + , _undef( true ) + {} + + /** + * Return the red component (0: none, 255: bright red). + **/ + uchar red() const { return _red; } + + /** + * Return the green component (0: none, 255: bright green). + **/ + uchar green() const { return _green; } + + /** + * Return the blue component (0: none, 255: bright blue). + **/ + uchar blue() const { return _blue; } + + /** + * Return 'true' if this color is undefined. + **/ + bool isUndefined() const { return _undef; } + + /** + * Return 'true' if this color is defined. + **/ + bool isDefined() const { return ! _undef; } + +private: + + uchar _red; + uchar _green; + uchar _blue; + + bool _undef; +}; + + +#endif // YColor_h diff --git a/src/YComboBox.cc b/src/YComboBox.cc new file mode 100644 index 0000000..ccd0894 --- /dev/null +++ b/src/YComboBox.cc @@ -0,0 +1,234 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YComboBox.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YComboBox.h" +#include "YUIException.h" + + +struct YComboBoxPrivate +{ + YComboBoxPrivate( bool editable ) + : editable( editable ) + , inputMaxLength( -1 ) + {} + + bool editable; + std::string validChars; + int inputMaxLength; +}; + + + + +YComboBox::YComboBox( YWidget * parent, const std::string & label, bool editable ) + : YSelectionWidget( parent, label, + true ) // enforceSingleSelection + , priv( new YComboBoxPrivate( editable ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YComboBox::~YComboBox() +{ + // NOP +} + + +bool YComboBox::editable() const +{ + return priv->editable; +} + + +std::string YComboBox::validChars() +{ + return priv->validChars; +} + + +void YComboBox::setValidChars( const std::string & newValidChars ) +{ + priv->validChars= newValidChars; +} + + +int YComboBox::inputMaxLength() const +{ + return priv->inputMaxLength; +} + + +void YComboBox::setInputMaxLength( int len ) +{ + priv->inputMaxLength = len; +} + + +std::string YComboBox::value() +{ + return text(); +} + + +void YComboBox::setValue( const std::string & newText ) +{ + YItem * item = findItem( newText ); + + if ( item ) + { + YSelectionWidget::deselectAllItems(); + item->setSelected(); + setText( item->label() ); + } + else + { + if ( editable() ) + setText( newText ); + else + { + YUI_THROW( YUIException( "Invalid value" ) ); + } + } +} + + +void YComboBox::selectItem( YItem * item, bool selected ) +{ + // Check against null pointer and if the item actually belongs to this + // widget, deselect any previously selected item and select the new one + YSelectionWidget::selectItem( item, selected ); + + if ( selected ) + { + setText( item->label() ); + } +} + + +YItem * +YComboBox::selectedItem() +{ + std::string currentText = text(); + + // Make sure exactly this item is selected (and no other) + YSelectionWidget::deselectAllItems(); + + // Try to find an item with this text + YItem * item = findItem( currentText ); + + if ( item ) + { + item->setSelected( true ); + return item; + } + + return 0; +} + + +YItemCollection +YComboBox::selectedItems() +{ + YItemCollection selectedItems; + + // There can be no more than one selected item + YItem * item = selectedItem(); + + if ( item ) + selectedItems.push_back( item ); + + return selectedItems; +} + + +const YPropertySet & +YComboBox::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property itemID | std::string Value ID of the selected item or the text the user entered + * @property std::string Label caption above the combo box + * @property itemList Items All items + * @property std::string ValidChars set of valid input characters + * @property integer InputMaxLength maximum number of input characters + * @property std::string IconPath Base path for icons + */ + propSet.add( YProperty( YUIProperty_Value, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_ValidChars, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_InputMaxLength, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YComboBox::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) return false; // Need special handling + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_ValidChars ) setValidChars( val.stringVal() ); + else if ( propertyName == YUIProperty_InputMaxLength ) setInputMaxLength( val.integerVal() ); + else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YComboBox::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_ValidChars ) return YPropertyValue( validChars() ); + else if ( propertyName == YUIProperty_InputMaxLength ) return YPropertyValue( inputMaxLength() ); + else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YComboBox.h b/src/YComboBox.h new file mode 100644 index 0000000..416359a --- /dev/null +++ b/src/YComboBox.h @@ -0,0 +1,243 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YComboBox.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YComboBox_h +#define YComboBox_h + +#include "YSelectionWidget.h" + +class YComboBoxPrivate; + + +/** + * ComboBox (or "drop down box", "drop down selection"); may be editable. + * + * A widget with a drop-down list of predefined values to select from. + * Optionally, this widget can be created in "editable" mode which means that + * the user can freely enter any text. + * + * In non-editable mode, a ComboBox works very much like a SelectionBox that + * uses fewer screen space. In that mode, it is recommended to use + * selectedItem() to retrieve its current value and selectItem() to set it. + * + * In editable mode, a ComboBox is more like an InputField with a list to pick + * predefined values from (for less typing). In that mode, it is recommended to + * use value() and setValue(). + * + * In either mode, it might be dangerous to use the iterators the + * (itemsBegin(), itemsEnd()) the base class (YSelectionWidget) provides to + * find the currently selected item: The items' "selected" flag may or may not + * be up to date. YComboBox::selectedItem() makes sure they are up to date. + **/ +class YComboBox : public YSelectionWidget +{ +protected: + /** + * Constructor. + * + * 'editable' means the user can freely enter any value without being + * restricted to the items of the ComboBox's list. + **/ + YComboBox( YWidget * parent, const std::string & label, bool editable ); + +public: + /** + * Destructor. + **/ + virtual ~YComboBox(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YComboBox"; } + + /** + * Return 'true' if this ComboBox is editable, i.e. if the user can freely + * enter any value without being restricted to the items of the ComboBox's + * list. + * + * Notice that this can only be set in the constructor. + **/ + bool editable() const; + + /** + * Return the value of this ComboBox: + * + * The text of a list item if the user (or the appplication) selected a + * list item or the content of the ComboBox's input field if the ComboBox + * is editable and the user (or the application) entered text there. + * + * See also YComboBox::selectedItem(). + **/ + std::string value(); + + /** + * Set the value of this ComboBox by string: Try to find a list item with + * that label and select it. + * + * If there is no matching list item, editable ComboBoxes will set their + * input field to that text. Non-editable ComboBoxes will throw an + * exception. + * + * See also selectItem(). + **/ + void setValue( const std::string & newText ); + + /** + * Return the (first) selected item or 0 if none is selected or if this + * ComboBox is editable and the user entered something that does not match + * any of the ComboBox's list items (in that case, use value() instead). + * + * Reimplemented from YSelectionWidget for better reliability: This will + * compare an editable ComboBox's user input against the text labels of + * all items and try to return an item if there is any match. + **/ + virtual YItem * selectedItem(); + + /** + * Return all selected items. + * + * This is not particularly useful for ComboBoxes since there can be no + * more than one selected item anyway; * better use selectedItem() or + * value() instead. + * + * This function does not transfer ownership of those items to the caller, + * so don't try to delete them! + * + * Reimplemented from YSelectionWidget for better reliability. + **/ + virtual YItemCollection selectedItems(); + + /** + * Select or deselect an item. See also setValue(). + * + * Reimplemented from YSelectionWidget. + **/ + virtual void selectItem( YItem * item, bool selected = true ); + + /** + * Get the valid input characters. No input validation is performed (i.e., + * the user can enter anything) if this is empty. + * + * This is only meaningful for if the ComboBox is editable. + **/ + std::string validChars(); + + /** + * Set the valid input characters. No input validation is performed (i.e., + * the user can enter anything) if this is empty. + * + * This is only meaningful for if the ComboBox is editable. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setValidChars( const std::string & validChars ); + + /** + * The maximum input length, i.e., the maximum number of characters the + * user can enter. -1 means no limit. + * + * This is only meaningful for if the ComboBox is editable. + **/ + int inputMaxLength() const; + + /** + * Set the maximum input length, i.e., the maximum number of characters the + * user can enter. -1 means no limit. + * + * This is only meaningful for if the ComboBox is editable. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setInputMaxLength( int numberOfChars ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + +protected: + + /** + * Return this ComboBox's current value as text. + * + * Called internally from value(), selectedItem() and related. + * + * Derived classes are required to implement this function. + **/ + virtual std::string text() = 0; + + /** + * + * Set this ComboBox's current value as text. + * + * Called internally whenever the content is to change + * programmatically. Don't call setValue() or selectItem() from here. + * + * Derived classes are required to implement this function. + **/ + virtual void setText( const std::string & newText ) = 0; + + +private: + + ImplPtr priv; +}; + + +#endif // YComboBox_h diff --git a/src/YCommandLine.cc b/src/YCommandLine.cc new file mode 100644 index 0000000..4ed1eda --- /dev/null +++ b/src/YCommandLine.cc @@ -0,0 +1,145 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YCommandLine.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include // malloc() +#include // strdup() + +#include +#include + +#include "YCommandLine.h" +#include "YUIException.h" + +#define YUILogComponent "ui" +#include "YUILog.h" + + +struct YCommandLinePrivate +{ + std::vector args; +}; + + + + + +YCommandLine::YCommandLine() + : priv( new YCommandLinePrivate() ) +{ + YUI_CHECK_NEW( priv ); + + std::ifstream cmdline( "/proc/self/cmdline", std::ifstream::in | std::ifstream::binary ); + + while ( cmdline.good() ) + { + std::string arg; + getline( cmdline, arg, '\0' ); + + if ( ! arg.empty() ) + { + yuiDebug() << "Arg #" << priv->args.size() + << ": \"" << arg << "\"" << std::endl; + + priv->args.push_back( arg ); + } + } +} + + +YCommandLine::~YCommandLine() +{ + +} + + +int +YCommandLine::argc() const +{ + return priv->args.size(); +} + + +char ** +YCommandLine::argv() const +{ + char ** argArray = (char **) ( malloc( argc() * sizeof( char * ) ) ); + + if ( argArray ) + { + for ( int i=0; i < argc(); i++ ) + { + argArray[ i ] = strdup( priv->args[i].c_str() ); + } + } + + return argArray; +} + + +void +YCommandLine::add( const std::string & arg ) +{ + priv->args.push_back( arg ); +} + + +std::string +YCommandLine::arg( int index ) const +{ + YUI_CHECK_INDEX( index, 0, (int) priv->args.size()-1 ); + + return priv->args[ index ]; +} + + +void +YCommandLine::remove( int index ) +{ + YUI_CHECK_INDEX( index, 0, (int) priv->args.size()-1 ); + + priv->args.erase( priv->args.begin() + index ); +} + + +void +YCommandLine::replace( int index, const std::string & newArg ) +{ + YUI_CHECK_INDEX( index, 0, (int) priv->args.size()-1 ); + + priv->args[ index ] = newArg; +} + + +int +YCommandLine::find( const std::string & argName ) const +{ + for ( int i=0; i < argc(); i++ ) + { + if ( priv->args[i] == argName ) + return i; + } + + return -1; +} diff --git a/src/YCommandLine.h b/src/YCommandLine.h new file mode 100644 index 0000000..70cb4fe --- /dev/null +++ b/src/YCommandLine.h @@ -0,0 +1,123 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YCommandLine.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YCommandLine_h +#define YCommandLine_h + +#include +#include "ImplPtr.h" + +class YCommandLinePrivate; + + +/** + * Utility class to access /proc//cmdline to retrieve argc and argv + **/ +class YCommandLine +{ +public: + /** + * Constructor. This will read /proc//cmdline of this process. + **/ + YCommandLine(); + + /** + * Destructor. + **/ + ~YCommandLine(); + + /** + * Return the number of arguments in the command line. + * Remember that the command itself (the binary of the process) is + * included, so a value of 1 (not 0!) means "no additional arguments". + **/ + int argc() const; + + /** + * Return the arguments in a C compatible fashion: An array of pointers to + * characters. The data are copied with strdup(), so they are valid beyond + * the life time of this object (but OTOH should be released with free() at + * some point). + **/ + char ** argv() const; + + /** + * Alias for argc() for those who like a more C++ -like syntax. + **/ + int size() const { return argc(); } + + /** + * Return command line argument no. 'index' (from 0 on). + * + * This might throw an YUIIndexOutOfRangeException. + **/ + std::string arg( int index ) const; + + /** + * Return command line argument no. 'index' (from 0 on) as operator[]: + * + * for ( int i=0; i < cmdLine.argc(); i++ ) + * cout << cmdLine[i] << std::endl; + * + * This might throw an YUIIndexOutOfRangeException. + **/ + std::string operator[]( int index ) const + { return arg( index ); } + + /** + * Add a command line argument (at the end of the existing ones). + **/ + void add( const std::string & arg ); + + /** + * Remove command line argument no. 'index' (from 0 on). + * + * This might throw an YUIIndexOutOfRangeException. + **/ + void remove( int index ); + + /** + * Replace command line argument no. 'index' (from 0 on) with 'arg'. + * + * This might throw an YUIIndexOutOfRangeException. + **/ + void replace( int index, const std::string & arg ); + + /** + * Find a command line argument 'argName' ("-display" etc.). + * Notice that leading minus signs must be specified in 'argName'. + * Since argv[0] is the program name, the search starts from argv[1]. + * + * Return the position of 'argName' (from 0 on) or -1 if not found. + **/ + int find( const std::string & argName ) const; + + +private: + + ImplPtr priv; +}; + + +#endif // YCommandLine_h diff --git a/src/YContextMenu.cc b/src/YContextMenu.cc new file mode 100644 index 0000000..838196b --- /dev/null +++ b/src/YContextMenu.cc @@ -0,0 +1,203 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YContextMenu.cc + + Author: Thomas Goettlicher + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YContextMenu.h" +#include "YMenuItem.h" + + +struct YContextMenuPrivate +{ + YContextMenuPrivate() + : nextSerialNo( 0 ) + {} + + int nextSerialNo; +}; + + + + +YContextMenu::YContextMenu( ) + : YSelectionWidget( NULL, "test", + false ) // enforceSingleSelection + , priv( new YContextMenuPrivate() ) +{ + YUI_CHECK_NEW( priv ); +} + + +YContextMenu::~YContextMenu() +{ + // NOP +} + + +void +YContextMenu::addItems( const YItemCollection & itemCollection ) +{ + YSelectionWidget::addItems( itemCollection ); + resolveShortcutConflicts(); + rebuildMenuTree(); +} + + +void +YContextMenu::addItem( YItem * item ) +{ + YSelectionWidget::addItem( item ); + item->setIndex( ++(priv->nextSerialNo) ); + + if ( item->hasChildren() ) + assignUniqueIndex( item->childrenBegin(), item->childrenEnd() ); +} + + +void +YContextMenu::assignUniqueIndex( YItemIterator begin, YItemIterator end ) +{ + for ( YItemIterator it = begin; it != end; ++it ) + { + YItem * item = *it; + + item->setIndex( ++(priv->nextSerialNo) ); + + if ( item->hasChildren() ) + assignUniqueIndex( item->childrenBegin(), item->childrenEnd() ); + } +} + + +void +YContextMenu::deleteAllItems() +{ + YSelectionWidget::deleteAllItems(); + priv->nextSerialNo = 0; +} + + +YMenuItem * +YContextMenu::findMenuItem( int index ) +{ + return findMenuItem( index, itemsBegin(), itemsEnd() ); +} + + +YMenuItem * +YContextMenu::findMenuItem( int wantedIndex, YItemConstIterator begin, YItemConstIterator end ) +{ + for ( YItemConstIterator it = begin; it != end; ++it ) + { + YMenuItem * item = dynamic_cast (*it); + + if ( item ) + { + if ( item->index() == wantedIndex ) + return item; + + if ( item->hasChildren() ) + { + YMenuItem * result = findMenuItem( wantedIndex, item->childrenBegin(), item->childrenEnd() ); + + if ( result ) + return result; + } + } + } + + return 0; +} + + +void +YContextMenu::resolveShortcutConflicts() +{ + // TO DO + // TO DO + // TO DO + + // For every menu level, make sure keyboard shortcuts are unique within that menu level. + // If necessary, change some of them (move the '&' character to some other character). + + + // See YShortcutManager for more hints. +} + + +const YPropertySet & +YContextMenu::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Label Label on the menu button + * @property itemList Items All menu items and submenus + * @property std::string IconPath Base path for icons (on menu items) + */ + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YContextMenu::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YContextMenu::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YContextMenu.h b/src/YContextMenu.h new file mode 100644 index 0000000..a4acb1c --- /dev/null +++ b/src/YContextMenu.h @@ -0,0 +1,188 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YContextMenu.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YContextMenu_h +#define YContextMenu_h + +#include "YSelectionWidget.h" +#include "YMenuItem.h" + +class YMenuItem; +class YContextMenuPrivate; + + +/** + * ContextMenu: Similar to PushButton, but with several actions: Upon clicking + * on a ContextMenu (or activating it with the keyboard), a pop-up menu opens + * where the user can activate an action. Menu items in that pop-up menu can + * have submenus (that will pop up in separate pop-up menus). + * + * Internally, this widget is more similar to the Tree widget. The difference + * is that it does not keep a "selected" status, but triggers an action right + * away, just like a PushButton. Like PushButton, ContextMenu sends an event + * right away when the user selects an item (clicks on a menu item or activates + * it with the keyboard). Items that have a submenu never send an event, they + * simply open their submenu when activated. + * + * Note: unlike other widgets, this one is not created via YWidgetFactory + * or YOptionalWidgetFactory but with YApplication::openContextMenu() + **/ +class YContextMenu : public YSelectionWidget +{ +protected: + /** + * Constructor. + * + * 'label' is the user-visible text on the button (not above it like all + * other SelectionWidgets). + **/ + YContextMenu(); + +public: + /** + * Destructor. + **/ + virtual ~YContextMenu(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YContextMenu"; } + + /** + * Rebuild the displayed menu tree from the internally stored YMenuItems. + * + * The application should call this (once) after all items have been added + * with addItem(). YContextMenu::addItems() calls this automatically. + * + * Derived classes are required to implement this. + **/ + virtual void rebuildMenuTree() = 0; + + /** + * Add multiple items. For some UIs, this can be more efficient than + * calling addItem() multiple times. This function also automatically calls + * resolveShortcutConflicts() and rebuildMenuTree() at the end. + * + * Derived classes can overwrite this function, but they should call this + * base class function at the end of the new implementation. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void addItems( const YItemCollection & itemCollection ); + + /** + * Add one item. This widget assumes ownership of the item object and will + * delete it in its destructor. + * + * This reimplementation will an index to the item that is unique for all + * items in this ContextMenu. That index can be used later with + * findMenuItem() to find the item by that index. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void addItem( YItem * item_disown ); + + /** + * Delete all items. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void deleteAllItems(); + + /** + * Resolve keyboard shortcut conflicts: Change shortcuts of menu items if + * there are duplicates in the respective menu level. + * + * This has to be called after all items are added, but before rebuildMenuTree() + * (see above). YContextMenu::addItems() calls this automatically. + **/ + void resolveShortcutConflicts(); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + +protected: + + /** + * Recursively find the first menu item with the specified index. + * Returns 0 if there is no such item. + **/ + YMenuItem * findMenuItem( int index ); + + /** + * Recursively find the first menu item with the specified index + * from iterator 'begin' to iterator 'end'. + * + * Returns 0 if there is no such item. + **/ + YMenuItem * findMenuItem( int index, YItemConstIterator begin, YItemConstIterator end ); + + /** + * Alias for findMenuItem(). Reimplemented to ensure consistent behaviour + * with YSelectionWidget::itemAt(). + **/ + YMenuItem * itemAt( int index ) + { return findMenuItem( index ); } + +private: + + /** + * Assign a unique index to all items from iterator 'begin' to iterator 'end'. + **/ + void assignUniqueIndex( YItemIterator begin, YItemIterator end ); + + + ImplPtr priv; +}; + + +#endif // YContextMenu_h diff --git a/src/YDateField.cc b/src/YDateField.cc new file mode 100644 index 0000000..d48ed08 --- /dev/null +++ b/src/YDateField.cc @@ -0,0 +1,62 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDateField.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YDateField.h" + + +struct YDateFieldPrivate +{ + YDateFieldPrivate() + {} + + bool dummy; +}; + + + + +YDateField::YDateField( YWidget * parent, const std::string & label ) + : YSimpleInputField( parent, label ) + , priv( new YDateFieldPrivate() ) +{ + YUI_CHECK_NEW( priv ); +} + + +YDateField::~YDateField() +{ + // NOP +} + + +/* + * Properties (all handled in YSimpleInputField): + * + * @property std::string Value the date (the field's contents) as "YYYY-MM-DD" + * @property std::string Label caption above the input field + */ diff --git a/src/YDateField.h b/src/YDateField.h new file mode 100644 index 0000000..e5a468d --- /dev/null +++ b/src/YDateField.h @@ -0,0 +1,69 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDateField.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YDateField_h +#define YDateField_h + +#include "YSimpleInputField.h" + +class YDateFieldPrivate; + +/** + * Input field for entering a date. + * + * Derived classes are required to implement: + * value() + * setValue() + * + * For both methods the date is formatted as "YYYY-MM-DD". + * See YSimpleInputField.h for more details. + **/ +class YDateField : public YSimpleInputField +{ +protected: + /** + * Constructor. + **/ + YDateField( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YDateField(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YDateField"; } + + +private: + + ImplPtr priv; +}; + + +#endif // YDateField_h diff --git a/src/YDialog.cc b/src/YDialog.cc new file mode 100644 index 0000000..9d7a1e5 --- /dev/null +++ b/src/YDialog.cc @@ -0,0 +1,823 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDialog.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YDialog.h" +#include "YEvent.h" +#include "YShortcutManager.h" +#include "YPushButton.h" +#include "YButtonBox.h" + +#include "YUI.h" +#include "YApplication.h" +#include "YWidgetFactory.h" +#include "YOptionalWidgetFactory.h" +#include "YLayoutBox.h" +#include "YRichText.h" +#include "YAlignment.h" +#include "YUIException.h" +#include "YEventFilter.h" +#include "YWidgetID.h" +#include "YDumbTab.h" + +// needed in order to read release notes +#include +#include +#include + +#define VERBOSE_DIALOGS 0 +#define VERBOSE_DISCARDED_EVENTS 0 +#define VERBOSE_EVENTS 0 + + +typedef std::list YEventFilterList; + + +struct YDialogPrivate +{ + YDialogPrivate( YDialogType dialogType, YDialogColorMode colorMode ) + : dialogType( dialogType ) + , colorMode( colorMode ) + , shortcutCheckPostponed( false ) + , defaultButton( 0 ) + , isOpen( false ) + , lastEvent( 0 ) + {} + + YDialogType dialogType; + YDialogColorMode colorMode; + bool shortcutCheckPostponed; + YPushButton * defaultButton; + bool isOpen; + YEvent * lastEvent; + YEventFilterList eventFilterList; +}; + + + +/** + * Helper class: Event filter that handles "Help" buttons. + **/ +class YHelpButtonHandler: public YEventFilter +{ +public: + YHelpButtonHandler( YDialog * dialog ) + : YEventFilter( dialog ) + {} + + virtual ~YHelpButtonHandler() {} + + YEvent * filter( YEvent * event ) + { + if ( event && event->widget() ) + { + YPushButton * button = dynamic_cast ( event->widget() ); + + if ( button && button->isHelpButton() ) + { + if ( YDialog::showHelpText( button ) ) + { + event = 0; // consume event + } + } + } + + return event; + } +}; + +/** + * Helper class: Event filter that handles "ReleaseNotes" buttons. + **/ +class YRelNotesButtonHandler: public YEventFilter +{ +public: + YRelNotesButtonHandler( YDialog * dialog ) + : YEventFilter( dialog ) + {} + + virtual ~YRelNotesButtonHandler() {} + + YEvent * filter( YEvent * event ) + { + if ( event && event->widget() ) + { + YPushButton * button = dynamic_cast ( event->widget() ); + + if ( button && button->isRelNotesButton() ) + { + if ( YDialog::showRelNotesText() ) + { + event = 0; // consume event + } + } + } + + return event; + } +}; + + + + +YDialog::YDialog( YDialogType dialogType, YDialogColorMode colorMode ) + : YSingleChildContainerWidget( 0 ) + , priv( new YDialogPrivate( dialogType, colorMode ) ) +{ + YUI_CHECK_NEW( priv ); + + _dialogStack.push( this ); + +#if VERBOSE_DIALOGS + yuiDebug() << "New " << this << std::endl; +#endif + + new YHelpButtonHandler( this ); + new YRelNotesButtonHandler( this ); +} + + +YDialog::~YDialog() +{ +#if VERBOSE_DIALOGS + yuiDebug() << "Destroying " << this << std::endl; +#endif + + // Inform attached classes that this dialog is in the process of being + // destroyed. This also happens in the base class destructor, but that + // might be too late. + setBeingDestroyed(); + + if ( priv->lastEvent ) + deleteEvent( priv->lastEvent ); + + // The base class also deletes all children, but this should be done before + // the event filters are deleted to prevent duplicate event filter deletion + // from (a) child widget destructors and (b) here. + deleteChildren(); + + // Delete the remaining event filters: Those installed by this dialog and + // those installed by some child widget that are not deleted yet. + deleteEventFilters(); + + if ( ! _dialogStack.empty() && _dialogStack.top() == this ) + { + _dialogStack.pop(); + + if ( ! _dialogStack.empty() ) + _dialogStack.top()->activate(); + } + else + yuiError() << "Not top of dialog stack: " << this << std::endl; +} + + +void +YDialog::open() +{ + if ( priv->isOpen ) + return; + + checkShortcuts(); + setInitialSize(); + openInternal(); // Make sure this is only called once! + + priv->isOpen = true; +} + + +bool +YDialog::isOpen() const +{ + return priv->isOpen; +} + + +bool +YDialog::isTopmostDialog() const +{ + if ( _dialogStack.empty() ) + { + yuiError() << "Dialog stack empty, but dialog existing: " << this << std::endl; + return false; + } + + return _dialogStack.top() == this; +} + + +void +YDialog::deleteEventFilters() +{ + while ( ! priv->eventFilterList.empty() ) + { + YEventFilter * filter = priv->eventFilterList.back(); + +#if VERBOSE_DIALOGS + yuiDebug() << "Deleting event filter " << std::std::hex << filter << std::dec << std::endl; +#endif + delete filter; + } +} + + +bool +YDialog::destroy( bool doThrow ) +{ + YUI_CHECK_WIDGET( this ); + + if ( isTopmostDialog() ) + { + delete this; + + return true; + } + else + { + if ( doThrow ) + YUI_THROW( YUIDialogStackingOrderException() ); + + return false; + } +} + + +YDialogType +YDialog::dialogType() const +{ + return priv->dialogType; +} + + +bool +YDialog::isMainDialog() +{ + switch ( priv->dialogType ) + { + case YMainDialog: return true; + case YWizardDialog: return true; + case YPopupDialog: return false; + + // Intentionally omitting the 'default' case so the compiler can + // catch unhandled enum values + } + + /*NOTREACHED*/ + return false; +} + + +YDialogColorMode +YDialog::colorMode() const +{ + return priv->colorMode; +} + + +void +YDialog::postponeShortcutCheck() +{ + priv->shortcutCheckPostponed = true; +} + + +bool +YDialog::shortcutCheckPostponed() const +{ + return priv->shortcutCheckPostponed; +} + + +void +YDialog::checkShortcuts( bool force ) +{ + if ( priv->shortcutCheckPostponed && ! force ) + { + yuiDebug() << "Shortcut check postponed" << std::endl; + } + else + { + + YShortcutManager shortcutManager( this ); + shortcutManager.checkShortcuts(); + + priv->shortcutCheckPostponed = false; + } +} + + +YPushButton * +YDialog::defaultButton() const +{ + return priv->defaultButton; +} + + +void +YDialog::setDefaultButton( YPushButton * newDefaultButton ) +{ + if ( newDefaultButton && priv->defaultButton ) // already have one? + { + yuiError() << "Too many `opt(`default) PushButtons: [" + << newDefaultButton->label() + << "]" << std::endl; + } + + priv->defaultButton = newDefaultButton; +} + + +void +YDialog::setInitialSize() +{ +#if VERBOSE_DIALOGS + yuiDebug() << "Setting initial size for " << this << std::endl; +#endif + + // Trigger geometry management + setSize( preferredWidth(), preferredHeight() ); +} + + +void +YDialog::recalcLayout() +{ + yuiDebug() << "Recalculating layout for " << this << std::endl; + + setSize( preferredWidth(), preferredHeight() ); +} + + +YEvent * +YDialog::waitForEvent( int timeout_millisec ) +{ + if ( ! isTopmostDialog() ) + YUI_THROW( YUIDialogStackingOrderException() ); + + if ( timeout_millisec < 0 ) + timeout_millisec = 0; + + if ( ! isOpen() ) + open(); + + if ( shortcutCheckPostponed() ) + { + yuiError() << "Performing missing keyboard shortcut check now in " + << this << std::endl; + + checkShortcuts( true ); + } + + deleteEvent( priv->lastEvent ); + YEvent * event = 0; + + do + { + event = filterInvalidEvents( waitForEventInternal( timeout_millisec ) ); + event = callEventFilters( event ); + + // If there was no event, if filterInvalidEvents() discarded an invalid + // event, or if one of the event filters consumed an event, go back and + // get the next event. + + } while ( ! event ); + + priv->lastEvent = event; + + return event; +} + + +YEvent * +YDialog::pollEvent() +{ + if ( ! isTopmostDialog() ) + YUI_THROW( YUIDialogStackingOrderException() ); + + if ( ! isOpen() ) + open(); + + YEvent * event = filterInvalidEvents( pollEventInternal() ); + + if ( event ) // Optimization (calling with 0 wouldn't hurt) + event = callEventFilters( event ); + + priv->lastEvent = event; + + // Nevermind if filterInvalidEvents() discarded an invalid event. + // pollInput() is normally called very often (in a loop), and most of the + // times it returns 0 anyway, so there is no need to care for just another + // 0 that is returned in this exotic case. + + return event; +} + + +YEvent * +YDialog::filterInvalidEvents( YEvent * event ) +{ + if ( ! event ) + return 0; + + YWidgetEvent * widgetEvent = dynamic_cast (event); + + if ( widgetEvent && widgetEvent->widget() ) + { + if ( ! widgetEvent->widget()->isValid() ) + { + /** + * Silently discard events from widgets that have become invalid. + * + * This may legitimately happen if some widget triggered an event yet + * nobody cared for that event (i.e. called UserInput() or PollInput() ) + * and the widget has been destroyed meanwhile. + **/ + + // yuiDebug() << "Discarding event for widget that has become invalid" << std::endl; + + deleteEvent( widgetEvent ); + return 0; + } + + if ( widgetEvent->widget()->findDialog() != this ) + { + /** + * Silently discard events from all but the current (topmost) dialog. + * + * This may happen even here even though the specific UI should have + * taken care about that: Events may still be in the queue. They might + * have been valid (i.e. belonged to the topmost dialog) when they + * arrived, but maybe simply nobody has evaluated them. + **/ + + // Yes, really yuiDebug() - this may legitimately happen. + yuiDebug() << "Discarding event from widget from foreign dialog" << std::endl; + +#if VERBOSE_DISCARDED_EVENTS + yuiDebug() << "Expected: " << this + << ", received: " << widgetEvent->widget()->findDialog() + << std::endl; + + yuiDebug() << "Event widget: " << widgetEvent->widget() << std::endl; + yuiDebug() << "From:" << std::endl; + widgetEvent->widget()->findDialog()->dumpWidgetTree(); + yuiDebug() << "Current dialog:" << std::endl; + dumpWidgetTree(); +#endif + + activate(); // try to force this dialog to the foreground + + deleteEvent( widgetEvent ); + return 0; + } + + } + + return event; +} + + +void +YDialog::deleteEvent( YEvent * event ) +{ + if ( event == priv->lastEvent ) + priv->lastEvent = 0; + + if ( event ) + { + if ( event->isValid() ) + { +#if VERBOSE_EVENTS + yuiDebug() << "Deleting " << event << std::endl; +#endif + delete event; + } + else + { + yuiError() << "Attempt to delete invalid event " << event << std::endl; + } + } +} + + +YDialog * +YDialog::currentDialog( bool doThrow ) +{ + if ( _dialogStack.empty() ) + { + if ( doThrow ) + YUI_THROW( YUINoDialogException() ); + return 0; + } + else + return _dialogStack.top(); +} + + +bool +YDialog::deleteTopmostDialog( bool doThrow ) +{ + if ( _dialogStack.empty() ) + { + if ( doThrow ) + YUI_THROW( YUINoDialogException() ); + } + else + { + delete _dialogStack.top(); + } + + return ! _dialogStack.empty(); +} + + +void +YDialog::deleteAllDialogs() +{ + while ( ! _dialogStack.empty() ) + { + delete _dialogStack.top(); + } +} + + +void +YDialog::deleteTo( YDialog * targetDialog ) +{ + YUI_CHECK_WIDGET( targetDialog ); + + while ( ! _dialogStack.empty() ) + { + YDialog * dialog = _dialogStack.top(); + + delete dialog; + + if ( dialog == targetDialog ) + return; + } + + // If we ever get here, targetDialog was nowhere in the dialog stack. + + YUI_THROW( YUIDialogStackingOrderException() ); +} + + +int +YDialog::openDialogsCount() +{ + return _dialogStack.size(); +} + + +void +YDialog::addEventFilter( YEventFilter * eventFilter ) +{ + YUI_CHECK_PTR( eventFilter ); + + if ( find( priv->eventFilterList.begin(), priv->eventFilterList.end(), + eventFilter ) != priv->eventFilterList.end() ) + { + yuiError() << "event filter " << std::hex << eventFilter << std::dec + << " already added to " << this + << std::endl; + } + else + { +#if VERBOSE_DIALOGS + yuiDebug() << "Adding event filter " << std::hex << eventFilter << std::dec << std::endl; +#endif + priv->eventFilterList.push_back( eventFilter ); + } +} + + +void +YDialog::removeEventFilter( YEventFilter * eventFilter ) +{ + YUI_CHECK_PTR( eventFilter ); + +#if VERBOSE_DIALOGS + yuiDebug() << "Removing event filter " << std::hex << eventFilter << std::dec << std::endl; +#endif + priv->eventFilterList.remove( eventFilter ); +} + + +YEvent * +YDialog::callEventFilters( YEvent * event ) +{ + YEventFilterList::const_iterator it = priv->eventFilterList.begin(); + + while ( it != priv->eventFilterList.end() && event ) + { + YEvent * oldEvent = event; + event = (*it)->filter( event ); + + if ( oldEvent != event ) // event filter consumed or changed the old event? + deleteEvent( oldEvent ); // get rid of the old one + + ++it; + } + + return event; +} + + +void +YDialog::showText( const std::string & text, bool useRichText ) +{ + + // set help text dialog size to 80% of topmost dialog, respectively 45x15 (default) + + unsigned int dialogWidth = 45; + unsigned int dialogHeight = 15; + + if ( ! _dialogStack.empty() ) + { + YDialog * dialog = _dialogStack.top(); + dialogWidth = (unsigned int) ( (float) dialog->preferredWidth() * 0.8 ); + dialogHeight = (unsigned int) ( (float) dialog->preferredHeight() * 0.8 ); + } + + // limit dialog to a reasonable size + if ( dialogWidth > 80 || dialogHeight > 25 ) + { + dialogWidth = 80; + dialogHeight = 25; + } + + try + { + YDialog * dialog = YUI::widgetFactory()->createPopupDialog(); + YAlignment * minSize = YUI::widgetFactory()->createMinSize( dialog, dialogWidth, dialogHeight ); + YLayoutBox * vbox = YUI::widgetFactory()->createVBox( minSize ); + YUI::widgetFactory()->createRichText( vbox, text, ! useRichText ); + YButtonBox * buttonBox = YUI::widgetFactory()->createButtonBox( vbox ); + YPushButton * okButton = YUI::widgetFactory()->createPushButton( buttonBox, "&OK" ); + okButton->setRole( YOKButton ); + okButton->setDefaultButton(); + + dialog->waitForEvent(); + dialog->destroy(); + } + catch ( const YUIException & exception ) + { + // Don't let the application die just because help couldn't be displayed. + + YUI_CAUGHT( exception ); + } +} + + +bool +YDialog::showHelpText( YWidget * widget ) +{ + std::string helpText; + + while ( widget ) + { + if ( ! widget->helpText().empty() ) + { + yuiDebug() << "Found help text for " << widget << std::endl; + helpText = widget->helpText(); + } + + widget = widget->parent(); + } + + if ( ! helpText.empty() ) + { + yuiMilestone() << "Showing help text" << std::endl; + showText( helpText, true ); + + yuiMilestone() << "Help dialog closed" << std::endl; + } + else // No help text + { + yuiWarning() << "No help text" << std::endl; + } + + return ! helpText.empty(); +} + +bool +YDialog::showRelNotesText() +{ + yuiMilestone() <<"Showing Release Notes" << std::endl; + + // set help text dialog size to 80% of topmost dialog, respectively 45x15 (default) + + unsigned int dialogWidth = 45; + unsigned int dialogHeight = 15; + + if ( ! _dialogStack.empty() ) + { + YDialog * dialog = _dialogStack.top(); + dialogWidth = (unsigned int) ( (float) dialog->preferredWidth() * 0.8 ); + dialogHeight = (unsigned int) ( (float) dialog->preferredHeight() * 0.8 ); + } + + // limit dialog to a reasonable size + if ( dialogWidth > 80 || dialogHeight > 25 ) + { + dialogWidth = 80; + dialogHeight = 25; + } + + try + { + std::map relnotes = YUI::application()->releaseNotes(); + if ( relnotes.size() == 0) + { + return false; + } + std::vector keys; + for(std::map::iterator it = relnotes.begin(); it != relnotes.end(); ++it) { + keys.push_back(it->first); + } + YDialog * dialog = YUI::widgetFactory()->createPopupDialog(); + YAlignment * minSize = YUI::widgetFactory()->createMinSize( dialog, dialogWidth, dialogHeight ); + YLayoutBox * vbox = YUI::widgetFactory()->createVBox( minSize ); + YDumbTab * rnTab = 0; + YRichText * richtext = 0; + + // both QT and NCurses do support DumbTab + if (relnotes.size() > 1 && YUI::optionalWidgetFactory()->hasDumbTab()) + { + rnTab = YUI::optionalWidgetFactory()->createDumbTab( vbox ); + int index = 0; + for(std::map::const_iterator it = relnotes.begin(); it != relnotes.end(); it++) + { + YItem * item = new YItem((*it).first ); + item->setIndex( index++ ); + rnTab->addItem( item ); + } + richtext = YUI::widgetFactory()->createRichText( rnTab, (*(relnotes.begin())).second, YUI::app()->isTextMode() ); + } + else + { + richtext = YUI::widgetFactory()->createRichText( vbox, (*(relnotes.begin())).second, YUI::app()->isTextMode() ); + } + YButtonBox * buttonBox = YUI::widgetFactory()->createButtonBox( vbox ); + YPushButton * okButton = YUI::widgetFactory()->createPushButton( buttonBox, "&OK" ); + okButton->setRole( YOKButton ); + okButton->setDefaultButton(); + + while(true) { + YEvent* event = dialog->waitForEvent(); + if ( event && event->eventType() == YEvent::MenuEvent && event->item()) + { + YItem * item = dynamic_cast ( event->item()); + richtext->setValue( relnotes[keys[item->index()]] ); + } + else if ( event && event->widget() ) + { + YPushButton * button = dynamic_cast ( event->widget() ); + if ( button ) + { + if ( button->role() == YOKButton) + { + break; + } + } + } + } + dialog->destroy(); + } + catch ( const YUIException & exception ) + { + // Don't let the application die just because RN couldn't be displayed. + + YUI_CAUGHT( exception ); + } + + return true; + +} diff --git a/src/YDialog.h b/src/YDialog.h new file mode 100644 index 0000000..66c25c0 --- /dev/null +++ b/src/YDialog.h @@ -0,0 +1,418 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDialog.h + + Author: Stefan Hundhammer + +/-*/ + + +#ifndef YDialog_h +#define YDialog_h + +#include "YSingleChildContainerWidget.h" +#include +#include + +class YShortcutManager; +class YPushButton; +class YDialogPrivate; +class YEvent; +class YEventFilter; + +// See YTypes.h for enum YDialogType and enum YDialogColorMode + + +/** + * A window in the desktop environment. + * A YPopupDialog always has a dedicated window + * but YMainDialog may be stacked in a single window. + **/ +class YDialog : public YSingleChildContainerWidget +{ +protected: + /** + * Constructor. + * + * 'dialogType' is one of YMainDialog or YPopupDialog. + * + * 'colorMode' can be set to YDialogWarnColor to use very bright "warning" + * colors or YDialogInfoColor to use more prominent, yet not quite as + * bright as "warning" colors. Use both only very rarely. + **/ + YDialog( YDialogType dialogType, + YDialogColorMode colorMode = YDialogNormalColor ); + + /** + * Destructor. + * Don't delete a dialog directly, use YDialog::deleteTopmostDialog() + * or YDialog::destroy(). + **/ + virtual ~YDialog(); + +public: + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YDialog"; } + + /** + * Open a newly created dialog: Finalize it and make it visible + * on the screen. + * + * Applications should call this once after all children are created. + * If the application doesn't do this, it will be done automatically upon + * the next call of YDialog::waitForEvent() (or related). This is OK if + * YDialog::waitForEvent() is called immediately after creating the dialog + * anyway. If it is not, the application might appear sluggish to the user. + * + * Derived classes are free to reimplement this, but they should call this + * base class method in the new implementation. + **/ + void open(); + + /** + * Return 'true' if open() has already been called for this dialog. + **/ + bool isOpen() const; + + /** + * Wait for a user event. In most cases, this means waiting until the user + * has clicked on a button in this dialog. If any widget has its 'notify' + * flag set (`opt(`notify) in YCP, setNotify( true ) in C++), an action on + * such a widget will also make waitForEvent() return. + * + * If the specified timeout elapses without any user event, a YTimeoutEvent + * will be returned. 0 means no timeout (wait forever). + * + * If open() has not been called for this dialog until now, + * it is called now. + * + * The dialog retains ownership of the event and will delete it upon the + * next call to waitForEvent() or pollEvent() or when the dialog is + * deleted. This also means that the return value of this function can + * safely be ignored without fear of memory leaks. + * + * Applications can create YEventFilters to act upon some events before + * they are delivered to the application. Each event filter of this dialog + * is called (in undefined order) in waitForEvent(). An event filter can + * consume an event (in which case waitForEvent() will return to its + * internal event loop), pass it through unchanged, or even replace it with + * a new event. Refer to the YEventFilter documentation for more details. + * + * If this dialog is not the topmost dialog, an exception is thrown. + **/ + YEvent * waitForEvent( int timeout_millisec = 0 ); + + /** + * Check if a user event is pending. If there is one, return it. + * If there is none, do not wait for one - return 0. + * + * If open() has not been called for this dialog until now, + * it is called now. + * + * The dialog retains ownership of the event and will delete it upon the + * next call to waitForEvent() or pollEvent() or when the dialog is + * deleted. This also means that the return value of this function can + * safely be ignored without fear of memory leaks. + * + * If this dialog is not the topmost dialog, an exception is thrown. + **/ + YEvent * pollEvent(); + + /** + * Return 'true' if this dialog is the topmost dialog. + **/ + bool isTopmostDialog() const; + + /** + * Close and delete this dialog (and all its children) if it is the topmost + * dialog. If this is not the topmost dialog, this will throw an exception + * if 'doThrow' is true (default). + * + * Remember that all pointers to the dialog and its children will be + * invalid after this operation. + * + * This is intentionally not named close() since close() would not imply + * that the dialog and its children are deleted. + * + * Returns 'true' upon success, 'false' upon failure. + **/ + bool destroy( bool doThrow = true ); + + /** + * Delete the topmost dialog. + * + * Will throw a YUINoDialogException if there is no dialog and 'doThrow' is + * 'true'. + * + * This is equivalent to YDialog::currentDialog()->destroy(). + * + * Returns 'true' if there is another open dialog after deleting, + * 'false' if there is none. + **/ + static bool deleteTopmostDialog( bool doThrow = true ); + + /** + * Delete all open dialogs. + **/ + static void deleteAllDialogs(); + + /** + * Delete all dialogs from the topmost to the one specified. + **/ + static void deleteTo( YDialog * dialog ); + + /** + * Returns the number of currently open dialogs (from 1 on), i.e., the + * depth of the dialog stack. + **/ + static int openDialogsCount(); + + /** + * Return the current (topmost) dialog. + * + * If there is none, throw a YUINoDialogException if 'doThrow' is 'true' + * and return 0 if 'doThrow' is false. + **/ + static YDialog * currentDialog( bool doThrow = true ); + + /** + * Alias for currentDialog(). + **/ + static YDialog * topmostDialog( bool doThrow = true ) + { return currentDialog( doThrow ); } + + /** + * Set the initial dialog size, depending on dialogType: + * YMainDialog dialogs get the UI's "default main window" size, + * YPopupDialog dialogs use their content's preferred size. + **/ + void setInitialSize(); + + /** + * Recalculate the layout of the dialog and of all its children after + * children have been added or removed or if any of them changed its + * preferred width of height. + * + * This is a very expensive operation. Call it only when really necessary. + * YDialog::open() includes a call to YDialog::setInitialSize() which does + * the same. + * + * The basic idea behind this function is to call it when the dialog + * changed after it (and its children hierarchy) was initially created. + **/ + void recalcLayout(); + + /** + * Return this dialog's type (YMainDialog / YPopupDialog /YWizardDialog). + **/ + YDialogType dialogType() const; + + /** + * Return 'true' if this dialog is a dialog of main dialog size: + * YMainDialog or YWizardDialog. + **/ + bool isMainDialog(); + + /** + * Return this dialog's color mode. + **/ + YDialogColorMode colorMode() const; + + /** + * Checks the keyboard shortcuts of widgets in this dialog unless shortcut + * checks are postponed or 'force' is 'true'. + * + * A forced shortcut check resets postponed checking. + **/ + void checkShortcuts( bool force = false ); + + /** + * From now on, postpone keyboard shortcut checks - i.e. normal (not + * forced) checkKeyboardShortcuts() will do nothing. Reset this mode by + * forcing a shortcut check with checkKeyboardShortcuts( true ). + **/ + void postponeShortcutCheck(); + + /** + * Return whether or not shortcut checking is currently postponed. + **/ + bool shortcutCheckPostponed() const; + + /** + * Return this dialog's default button: The button that is activated when + * the user hits [Return] anywhere in this dialog. Note that this is not + * the same as the button that currently has the keyboard focus. + * + * This might return 0 if there is no default button. + **/ + YPushButton * defaultButton() const; + + /** + * Delete an event. + **/ + void deleteEvent( YEvent * event ); + + /** + * Add an event filter. This can be useful to catch certain types of events + * before they are delivered to the application. All event filters are + * called (in unspecified order) in waitForEvent(). Each one may consume + * an event, pass it through unchanged, or replace it with a newly created + * event. + * + * Normally, an YEventFilter should be created on the heap with 'new'. In + * that case, the dialog's destructor will take care of deleting it. + * + * In rare cases it might make sense to create an YEventFilter on the stack + * (as a local variable) and rely on that variable to go out of scope and + * be destroyed before the dialog gets destroyed. But that may be risky. + * + * Notice that applications never need to call this function: YEventFilter + * does it automatically in its constructor. + **/ + void addEventFilter( YEventFilter * eventFilter ); + + /** + * Remove an event filter. + * + * Notice that applications never need to call this function: YEventFilter + * does it automatically in its destructor. + **/ + void removeEventFilter( YEventFilter * eventFilter ); + + /** + * Highlight a child widget of this dialog. This is meant for debugging: + * YDialogSpy and similar uses. + * + * No more than one widget can be highlighted at any one time in the same + * dialog. Highlighting another widget un-highlights a previously + * highlighted widget. 0 means 'unhighlight the last highlighted widget, + * but don't highlight any other'. + * + * This default implementation does nothing. + **/ + virtual void highlight( YWidget * child ) {} + + /** + * Set this dialog's default button (the button that is activated when + * the user hits [Return] anywhere in this dialog). 0 means no default + * button. + * + * There should be no more than one default button in a dialog. + * + * Derived classes are free to overwrite this method, but they should + * call this base class method in the new implementation. + **/ + virtual void setDefaultButton( YPushButton * defaultButton ); + + /** + * Activate this dialog: Make sure that it is shown as the topmost dialog + * of this application and that it can receive input. + * + * Derived classes are required to implement this. + **/ + virtual void activate() = 0; + + /** + * Show the specified text in a pop-up dialog with a local event loop. + * This is useful for help texts. + * 'richText' indicates if YRichText formatting should be applied. + **/ + static void showText( const std::string & text, bool richText = false ); + + /** + * Show the help text for the specified widget. If it doesn't have one, + * traverse up the widget hierarchy until there is one. + * + * If there is a help text, it is displayed in a pop-up dialog with a local + * event loop. + * + * This returns 'true' on success (there was a help text) and 'false' on + * failure (no help text). + **/ + static bool showHelpText( YWidget * widget ); + + /** + * Show the release notes + * + * If there are release notes, they are displayed in a pop-up dialog with a local + * event loop. + * + * This returns 'true' on success (there were relnotes) and 'false' on + * failure (no relnotes). + **/ + static bool showRelNotesText(); + + +protected: + + /** + * Internal open() method. This is called (exactly once during the life + * time of the dialog) in open(). + * + * Derived classes are required to implement this to do whatever is + * necessary to make this dialog visible on the screen. + **/ + virtual void openInternal() = 0; + + /** + * Wait for a user event. + * + * Derived classes are required to implement this. + **/ + virtual YEvent * waitForEventInternal( int timeout_millisec ) = 0; + + /** + * Check if a user event is pending. If there is one, return it. + * If there is none, do not wait for one - return 0. + * + * Derived classes are required to implement this. + **/ + virtual YEvent * pollEventInternal() = 0; + + /** + * Filter out invalid events: Return 0 if the event does not belong to this + * dialog or the unchanged event if it does. + **/ + YEvent * filterInvalidEvents( YEvent * event ); + + /** + * Call the installed event filters. + **/ + YEvent * callEventFilters( YEvent * event ); + + /** + * Delete all (remaining) event filters. + **/ + void deleteEventFilters(); + + /** + * Stack holding all currently existing dialogs. + **/ + static std::stack _dialogStack; + +private: + + ImplPtr priv; +}; + + +#endif // YDialog_h diff --git a/src/YDialogSpy.cc b/src/YDialogSpy.cc new file mode 100644 index 0000000..9dc1a69 --- /dev/null +++ b/src/YDialogSpy.cc @@ -0,0 +1,899 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDialogSpy.cc + + Author: Stefan Hundhammer + +/-*/ + +#include + +#define YUILogComponent "ui-dialog-spy" +#include "YUILog.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TREE_VWEIGHT 40 +#define PROP_VWEIGHT 60 + +#define DIA_HEIGHT 24 + +#define TREE_HEIGHT 10 +#define TREE_WIDTH 50 + +#define PROP_HEIGHT 12 +#define PROP_WIDTH 50 + +/** + * Custom tree item class to map tree items to widgets + **/ +class YWidgetTreeItem: public YTreeItem +{ +public: + YWidgetTreeItem( YWidget * widget, + bool isOpen ) + : YTreeItem( "", isOpen ) + , _widget( widget ) + { + setWidgetLabel(); + } + + YWidgetTreeItem( YWidgetTreeItem * parent, + YWidget * widget, + bool isOpen ) + : YTreeItem( parent, "", isOpen ) + , _widget( widget ) + { + setWidgetLabel(); + } + + virtual ~YWidgetTreeItem() {} + YWidget * widget() const { return _widget; } + + +protected: + + void setWidgetLabel() + { + std::ostringstream str; + str << _widget; + setLabel( str.str() ); + } + +private: + YWidget * _widget; +}; + + +static void fillTree( YWidgetTreeItem * parent, + YWidgetListConstIterator begin, + YWidgetListConstIterator end, + int treeLevel ); + + + + +class YDialogSpyPrivate +{ +public: + + YDialogSpyPrivate() + : targetDialog( nullptr ) + , spyDialog( nullptr ) + , widgetTree( nullptr ) + , propButton( nullptr ) + , propReplacePoint( nullptr ) + , propTable( nullptr ) + {} + + ~YDialogSpyPrivate(); + + YDialog * targetDialog; // Dialog that is being inspected + YDialog * spyDialog; // Debug dialog that shows widget data + YTree * widgetTree; // Tree widget to show widget hierarchy + YPushButton * propButton; + YMenuButton * addButton; + YPushButton * deleteButton; + YPushButton * upButton; + YPushButton * downButton; + YReplacePoint * propReplacePoint; + YTable * propTable; + YMenuItem *exportMenu; + + YWidget * selectedWidget(); + void selectedWidgetChanged(); + void refreshProperties(); + bool toggleProperties(); + void highlightWidget(bool enable = true); + + void deleteWidget(); + void addWidget(const std::string &type); + void editProperty(); + void moveSelectedUp() { moveSelected(MOVE_UP); } + void moveSelectedDown() { moveSelected(MOVE_DOWN); } + +private: + enum Direction + { + MOVE_UP = 0, + MOVE_DOWN + }; + + void moveSelected(Direction direction); + void showProperties(); + void hideProperties(); + bool propertiesShown() const; + void targetDialogUpdated(); + void refreshButtonStates(); + void editWidget(YWidget *widget, const std::string &property="Label"); +}; + +/** Destructor - switch off widget highlighting at the end +*/ +YDialogSpyPrivate::~YDialogSpyPrivate() +{ + highlightWidget(false); +} + +/** Fill the widget tree content +* @param target the target dialog which will be examined +* @param widgetTree where to display the structure +*/ +void fillWidgetTree(YDialog *target, YTree *widgetTree) +{ + YWidgetTreeItem * rootItem = new YWidgetTreeItem( target, true ); + YUI_CHECK_NEW( rootItem ); + fillTree( rootItem, target->childrenBegin(), target->childrenEnd(), 1 ); + widgetTree->addItem( rootItem ); + widgetTree->rebuildTree(); +} + +/** Constructor - create the main spy dialog +*/ +YDialogSpy::YDialogSpy( YDialog * targetDialog ) + : priv( new YDialogSpyPrivate() ) +{ + if ( ! targetDialog ) + targetDialog = YDialog::topmostDialog(); + + priv->targetDialog = targetDialog; + YWidgetFactory * fac = YUI::widgetFactory(); + + priv->spyDialog = fac->createPopupDialog(); + YAlignment * diaMin = fac->createMinHeight( priv->spyDialog, DIA_HEIGHT ); + YLayoutBox * vbox = fac->createVBox( diaMin ); + + auto alignment = fac->createLeft( vbox ); + auto fileMenu = fac->createMenuButton( alignment, "&File" ); + + YItemCollection items; + priv->exportMenu = new YMenuItem( "Export (TODO)" ); + items.push_back( priv->exportMenu ); + fileMenu->addItems( items ); + + auto minSize = fac->createMinSize( vbox, TREE_WIDTH, TREE_HEIGHT ); + minSize->setWeight( YD_VERT, TREE_VWEIGHT ); + priv->widgetTree = fac->createTree( minSize, "Widget &Tree", false ); + priv->widgetTree->setNotify( true ); + + fillWidgetTree(priv->targetDialog, priv->widgetTree); + + auto hbox = fac->createHBox( vbox ); + priv->propButton = fac->createPushButton( hbox, "&Properties >>>" ); + + priv->addButton = fac->createMenuButton( hbox, "&Add" ); + YItemCollection add_items; + YMenuItem *menu_info = new YMenuItem( "Info" ); + YMenuItem *menu_buttons = new YMenuItem( "Buttons" ); + YMenuItem *menu_input = new YMenuItem( "Input" ); + YMenuItem *menu_align = new YMenuItem( "Alignment" ); + YMenuItem *menu_size = new YMenuItem( "Size" ); + YMenuItem *menu_containers = new YMenuItem( "Containers" ); + YMenuItem *menu_special = new YMenuItem( "Special" ); + add_items.push_back( menu_info ); + add_items.push_back( menu_buttons ); + add_items.push_back( menu_input ); + add_items.push_back( menu_align ); + add_items.push_back( menu_size ); + add_items.push_back( menu_containers ); + add_items.push_back( menu_special ); + + new YMenuItem( menu_info, "Label" ); + new YMenuItem( menu_info, "Heading" ); + new YMenuItem( menu_info, "RichText" ); + new YMenuItem( menu_info, "ProgressBar" ); + new YMenuItem( menu_info, "BusyIndicator" ); + new YMenuItem( menu_info, "Table" ); + + new YMenuItem( menu_buttons, "PushButton" ); + new YMenuItem( menu_buttons, "CheckBox" ); + new YMenuItem( menu_buttons, "ComboBox" ); + new YMenuItem( menu_buttons, "MenuButton" ); + new YMenuItem( menu_buttons, "RadioButton" ); + + new YMenuItem( menu_input, "InputField" ); + new YMenuItem( menu_input, "IntField" ); + new YMenuItem( menu_input, "MultiLineEdit" ); + new YMenuItem( menu_input, "MultiSelectionBox" ); + new YMenuItem( menu_input, "Password" ); + new YMenuItem( menu_input, "SelectionBox" ); + + new YMenuItem( menu_align, "Left" ); + new YMenuItem( menu_align, "Right" ); + new YMenuItem( menu_align, "Top" ); + new YMenuItem( menu_align, "Bottom" ); + new YMenuItem( menu_align, "HCenter" ); + new YMenuItem( menu_align, "VCenter" ); + new YMenuItem( menu_align, "HVCenter" ); + + new YMenuItem( menu_size, "MinHeight" ); + new YMenuItem( menu_size, "MinWidth" ); + new YMenuItem( menu_size, "MinSize" ); + new YMenuItem( menu_size, "HSquash" ); + new YMenuItem( menu_size, "VSquash" ); + new YMenuItem( menu_size, "HVSquash" ); + new YMenuItem( menu_size, "HWeight" ); + new YMenuItem( menu_size, "VWeight" ); + + new YMenuItem( menu_containers, "MarginBox" ); + new YMenuItem( menu_containers, "ButtonBox" ); + new YMenuItem( menu_containers, "CheckBoxFrame" ); + new YMenuItem( menu_containers, "Frame" ); + new YMenuItem( menu_containers, "HBox" ); + new YMenuItem( menu_containers, "HSpacing" ); + new YMenuItem( menu_containers, "ReplacePoint" ); + new YMenuItem( menu_containers, "VBox" ); + new YMenuItem( menu_containers, "VSpacing" ); + + // TODO: these are not available in ncurses UI + new YMenuItem( menu_special, "BarGraph" ); + new YMenuItem( menu_special, "DateField" ); + new YMenuItem( menu_special, "DumbTab" ); + new YMenuItem( menu_special, "Graph" ); + new YMenuItem( menu_special, "Slider" ); + new YMenuItem( menu_input, "TimeField" ); + new YMenuItem( menu_special, "TimezoneSelector" ); + + priv->addButton->addItems( add_items ); + + priv->deleteButton = fac->createPushButton( hbox, "&Delete" ); + priv->upButton = fac->createPushButton( hbox, "⬆ Up" ); + priv->downButton = fac->createPushButton( hbox, "⬇ Down" ); + + priv->propReplacePoint = fac->createReplacePoint( vbox ); + fac->createEmpty( priv->propReplacePoint ); + + priv->selectedWidgetChanged(); +} + +/** + * Destructor + */ +YDialogSpy::~YDialogSpy() +{ + if ( priv->spyDialog ) + priv->spyDialog->destroy(); +} + +/** Is the property dialog displayed? + * @return true if the dialog is displayed + */ +bool YDialogSpyPrivate::propertiesShown() const +{ + return propTable != nullptr; +} + +/** + * Highlight the currently selected widget in the spy dialog + */ +void YDialogSpyPrivate::highlightWidget(bool enable) +{ + if (targetDialog) targetDialog->highlight( enable ? selectedWidget() : nullptr); +} + +/** + * Display details about the currently selected widget + */ +void YDialogSpyPrivate::showProperties() +{ + if ( propertiesShown() ) return; + + propReplacePoint->deleteChildren(); + propReplacePoint->setWeight( YD_VERT, PROP_VWEIGHT ); + + auto fac = YUI::widgetFactory(); + auto minSize = fac->createMinSize( propReplacePoint, + PROP_WIDTH, PROP_HEIGHT ); + auto header = new YTableHeader(); + YUI_CHECK_NEW( header ); + header->addColumn( "Property" ); + header->addColumn( "Value" ); + header->addColumn( "Type" ); + + propTable = fac->createTable( minSize, header ); + propTable->setNotify( true ); + + propButton->setLabel( "<<< &Properties" ); + propReplacePoint->showChild(); + spyDialog->recalcLayout(); +} + +/** + * Hide property details + */ +void YDialogSpyPrivate::hideProperties() +{ + if ( !propertiesShown() ) return; + + propReplacePoint->deleteChildren(); + propReplacePoint->setWeight( YD_VERT, 0 ); + propTable = nullptr; + YUI::widgetFactory()->createEmpty( propReplacePoint ); + + propButton->setLabel( "&Properties >>>" ); + propReplacePoint->showChild(); + spyDialog->recalcLayout(); +} + +/** + * Hide or show the properties dialog + * @return true if the dialog is now displayed + */ +bool YDialogSpyPrivate::toggleProperties() +{ + bool ret = !propertiesShown(); + + if (ret) + { + showProperties(); + refreshProperties(); + } + else + hideProperties(); + + return ret; +} + + +/** + * Refresh the displayed properties + */ +void YDialogSpyPrivate::refreshProperties() +{ + // properties shown? + if ( !propTable ) + return; + + propTable->deleteAllItems(); + auto widget = selectedWidget(); + + if ( !widget ) + return; + + YItemCollection items; + auto propSet = widget->propertySet(); + items.reserve( propSet.size() ); + + for ( YPropertySet::const_iterator it = propSet.propertiesBegin(); + it != propSet.propertiesEnd(); + ++it ) + { + YProperty prop = *it; + YPropertyValue propVal = widget->getProperty( prop.name() ); + std::string propValStr; + + switch ( prop.type() ) + { + case YStringProperty: + propValStr = propVal.stringVal(); + break; + + case YBoolProperty: + propValStr = propVal.boolVal() ? "true" : "false"; + break; + + case YIntegerProperty: + propValStr = std::to_string(propVal.integerVal()); + break; + + default: + propValStr = "???"; + break; + } + + auto item = new YTableItem( prop.name(), propValStr, prop.typeAsStr() ); + YUI_CHECK_NEW( item ); + items.push_back( item ); + } + + propTable->addItems( items ); + propTable->deselectAllItems(); +} + +/** + * Fill the widget tree dialog + * @param parent widget tree item + * @param begin iterator pointing to the first item + * @param end iterator pointing to the last item + * @param treeLevel current tree level (nesting) + */ +void fillTree( YWidgetTreeItem * parent, + YWidgetListConstIterator begin, + YWidgetListConstIterator end, + int treeLevel ) +{ + for ( YWidgetListConstIterator it = begin; it != end; ++it ) + { + YWidget * widget = *it; + auto item = new YWidgetTreeItem( parent, widget, treeLevel < 4 ); + + if ( widget->hasChildren() ) + fillTree( item, widget->childrenBegin(), widget->childrenEnd(), treeLevel+1 ); + } +} + +/** + * The main loop of the spy dialog + */ +void YDialogSpy::exec() +{ + YUI_CHECK_PTR( priv->spyDialog ); + + while ( true ) + { + auto event = priv->spyDialog->waitForEvent(); + yuiMilestone() << "event: " << event; + if (!event) continue; + + // window manager "close window" button + if ( event->eventType() == YEvent::CancelEvent ) break; + else if ( event->eventType() == YEvent::MenuEvent) + { + YMenuItem * menu_item = dynamic_cast(event->item()); + + // TODO: handle the export menu item + if (menu_item == priv->exportMenu) continue; + + // handle all unhandled menu items as "Add" menu items, this is much + // simpler than comparing it with the huge amount of menu item pointers + if (menu_item) + { + auto menu_label = menu_item->label(); + yuiMilestone() << "Activated menu item: " << menu_label << std::endl; + priv->addWidget(menu_label); + } + + continue; + } + + // just make sure we do not use NULL in some unexpected case + if (!event->widget()) continue; + + if ( event->widget() == priv->upButton ) priv->moveSelectedUp(); + else if ( event->widget() == priv->downButton) priv->moveSelectedDown(); + else if ( event->widget() == priv->propButton ) priv->toggleProperties(); + else if ( event->widget() == priv->deleteButton) priv->deleteWidget(); + else if ( event->widget() == priv->propTable ) priv->editProperty(); + else if ( event->widget() == priv->widgetTree ) priv->selectedWidgetChanged(); + } +} + +/** + * Run the spy dialog for selected UI dialog + * @param dialog UI dialog to examine + */ +void YDialogSpy::showDialogSpy( YDialog * dialog ) +{ + try + { + YDialogSpy dialogSpy( dialog ); + dialogSpy.exec(); + } + catch ( YUIException & exception ) + { + // ignore all YUI exceptions which might happen when playing with the layout + YUI_CAUGHT( exception ); + YPopupInternal::message("Error:\n" + exception.msg()); + } +} + +/** + * The currently selected wiget + * @return The currently selected widget (or nullptr if nothing is selected) + */ +YWidget * YDialogSpyPrivate::selectedWidget() +{ + auto item = dynamic_cast(widgetTree->selectedItem()); + + return item ? item->widget() : nullptr; +} + +/** + * The selected item has been changed, refresh the UI + */ +void YDialogSpyPrivate::selectedWidgetChanged() +{ + highlightWidget(); + refreshProperties(); + refreshButtonStates(); +} + +/** + * Run the property editor for the current widget + */ +void YDialogSpyPrivate::editProperty() +{ + auto selected_item = dynamic_cast(propTable->selectedItem()); + if (!selected_item) return; + + auto cell = selected_item->cell(0); + yuiMilestone() << "editing property: " << cell->label(); + + YPropertyEditor editor(selectedWidget()); + // update the property table when only the property has been changed + if (editor.edit(cell->label())) refreshProperties(); +} + +/** + * Delete the currently selected widget + */ +void YDialogSpyPrivate::deleteWidget() +{ + auto w = selectedWidget(); + if (!w) return; + + auto parent = w->parent(); + if (!parent) return; + + yuiMilestone() << "removing widget: " << w << std::endl; + parent->removeChild(w); + + if ( w->isValid() ) + { + delete w; + } + + // any other child left after the removal? + if (!parent->hasChildren()) + { + // add an Empty widget to have a valid widget tree + // e.g. empty VBoxes are not allowed + YUI::widgetFactory()->createEmpty(parent); + } + + targetDialogUpdated(); +} + +/** + * Helper method - Is the widget a VBox or Hbox? + * @param widget the widget + * @return true if the widget is a VBox or HBox + */ +bool isBox(const YWidget *widget) +{ + return dynamic_cast(widget); +} + +/** + * Helper method - Is the widget a VBox? + * @param widget the widget + * @return true if the widget is a VBox + */ +bool isVBox(const YWidget *widget) +{ + auto box = dynamic_cast(widget); + return box && box->primary() == YD_VERT; +} + +/** + * Move the selected widget up/left or down/right. The visual direction + * actually depends on the widget, it just moves the widget to the begining + * or the end of the container. + * @param true = up move to the begining (up/left), false = to the end (down/right) + */ +void YDialogSpyPrivate::moveSelected(Direction direction) +{ + auto target_widget = selectedWidget(); + if (!target_widget) return; + + auto parent = target_widget->parent(); + if (!parent || !isBox(parent)) return; + + if (direction == MOVE_UP) + { + // the first child cannot be moved further + if (target_widget == parent->firstChild()) return; + + auto i = find( parent->childrenBegin(), parent->childrenEnd(), target_widget ); + if (i != parent->childrenEnd()) + { + // swap with the preceeding widget + // Note: use a temporary variable to not rely on the argument evaluation order! + auto other = i--; + std::swap(*other, *i); + } + } + else + // moving down + { + // the last child cannot be moved further to the end + if (target_widget == parent->lastChild()) return; + + auto i = find( parent->childrenBegin(), parent->childrenEnd(), target_widget ); + if (i != parent->childrenEnd()) + { + // swap with the succeeding widget + // Note: use a temporary variable to not rely on the argument evaluation order! + auto other = i++; + std::swap(*other, *i); + } + } + + targetDialogUpdated(); +} + +/** + * Generic handler for adding widgets + * @param type Type of the widget to add + */ +void YDialogSpyPrivate::addWidget(const std::string &type) +{ + auto widget = selectedWidget(); + if (!widget) return; + + try + { + auto f = YUI::widgetFactory(); + + if (type == "Bottom") + editWidget(f->createBottom(widget)); + else if (type == "BusyIndicator") + editWidget(f->createBusyIndicator(widget, "Busy Indicator", 10000)); + else if (type == "ButtonBox") + editWidget(f->createButtonBox(widget)); + else if (type == "ComboBox") + { + auto cb = f->createComboBox(widget, "Combo Box"); + editWidget(cb); + + YPopupInternal::StringArray items(YPopupInternal::editNewStringArray("Menu Items")); + + YItemCollection add_items; + // access by reference + for(auto&& str: items) add_items.push_back( new YMenuItem( str ) ); + cb->addItems( add_items ); + } + else if (type == "Empty") + editWidget(f->createEmpty(widget)); + else if (type == "Frame") + editWidget(f->createFrame(widget, "Frame")); + else if (type == "HBox") + editWidget(f->createHBox(widget)); + else if (type == "Heading") + editWidget(f->createHeading(widget, "Heading")); + else if (type == "HSpacing") + editWidget(f->createHSpacing(widget)); + else if (type == "HStretch") + editWidget(f->createHStretch(widget)); + else if (type == "CheckBox") + editWidget(f->createCheckBox(widget, "Check Box")); + else if (type == "CheckBoxFrame") + // make it checked by default + editWidget(f->createCheckBoxFrame(widget, "Check Box Frame", true)); + else if (type == "Image") + editWidget(f->createImage(widget, "")); + else if (type == "InputField") + editWidget(f->createInputField(widget, "Input")); + else if (type == "IntField") + editWidget(f->createIntField(widget, "Integer Field", 0, 100, 50)); + else if (type == "Label") + editWidget(f->createLabel(widget, "Label")); + else if (type == "Left") + editWidget(f->createLeft(widget)); + else if (type == "LogView") + editWidget(f->createLogView(widget, "Log View", 12)); + else if (type == "MenuButton") + { + auto menu = f->createMenuButton( widget, "Menu" ); + editWidget(menu); + + YPopupInternal::StringArray items(YPopupInternal::editNewStringArray("Menu Items")); + + YItemCollection add_items; + // access by reference + for(auto&& str: items) add_items.push_back( new YMenuItem( str ) ); + menu->addItems( add_items ); + } + else if (type == "MinHeight") + editWidget(f->createMinHeight(widget, 10)); + else if (type == "MinWidth") + editWidget(f->createMinWidth(widget, 10)); + else if (type == "MinSize") + editWidget(f->createMinSize(widget, 10, 10)); + else if (type == "MultiLineEdit") + editWidget(f->createMultiLineEdit(widget, "MultiLineEdit")); + else if (type == "MultiSelectionBox") + { + auto msb = f->createMultiSelectionBox(widget, "MultiSelection Box"); + editWidget(msb); + + // edit the item list and update the widget after pressing OK + YPopupInternal::StringArray items(YPopupInternal::editNewStringArray("Items")); + // access by reference + for(auto&& str: items) msb->addItem(str); + } + else if (type == "OutputField") + editWidget(f->createOutputField(widget, "Output Field")); + else if (type == "Password") + editWidget(f->createPasswordField(widget, "Password")); + else if (type == "ProgressBar") + editWidget(f->createProgressBar(widget, "Progress")); + else if (type == "PushButton") + editWidget(f->createPushButton(widget, "Button")); + else if (type == "RadioButton") + editWidget(f->createRadioButton(widget, "Radio Button")); + else if (type == "RadioButtonGroup") + editWidget(f->createRadioButtonGroup(widget)); + else if (type == "ReplacePoint") + editWidget(f->createReplacePoint(widget)); + else if (type == "Right") + editWidget(f->createRight(widget)); + else if (type == "RichText") + editWidget(f->createRichText(widget, "This is a RichText.")); + else if (type == "SelectionBox") + editWidget(f->createSelectionBox(widget, "Selection Box")); + else if (type == "Table") + { + YPopupInternal::StringArray items(YPopupInternal::editNewStringArray("Table Columns")); + + // abort adding if Cancel has been pressed + if (!items.empty()) + { + auto header = new YTableHeader(); + + // access by reference + for(auto&& str: items) header->addColumn(str); + + editWidget(f->createTable(widget, header)); + } + } + else if (type == "Top") + editWidget(f->createTop(widget)); + else if (type == "Tree") + editWidget(f->createTree(widget, "Tree")); + else if (type == "VBox") + editWidget(f->createVBox(widget)); + else if (type == "VSpacing") + editWidget(f->createVSpacing(widget)); + else if (type == "VStretch") + editWidget(f->createVStretch(widget)); + else + { + YPopupInternal::message( + "Adding \"" + type + "\" widget type is not supported."); + return; + } + + targetDialogUpdated(); + } + catch( const YUIException & exception ) + { + YPopupInternal::message("Could not add a new widget:\n" + + exception.msg()); + } +} + +/** + * Refresh the target dialog after modifying it. + */ +void YDialogSpyPrivate::targetDialogUpdated() +{ + // redraw the target dialog + targetDialog->recalcLayout(); + + // refresh the spy dialog + widgetTree->deleteAllItems(); + fillWidgetTree(targetDialog, widgetTree); +} + +/** + * Refresh button states in the main spy dialog + */ +void YDialogSpyPrivate::refreshButtonStates() +{ + auto widget = selectedWidget(); + auto parent = widget ? widget->parent() : nullptr; + + // Enable the moving buttons ony when the selected widget is inside + // a VBox/HBox container, set the labels according to stacking direction. + if (widget && parent && isBox(parent)) + { + upButton->setEnabled(widget != parent->firstChild()); + upButton->setLabel(isVBox(parent) ? "⬆ Up" : "⬅ Left"); + downButton->setEnabled(widget != parent->lastChild()); + downButton->setLabel(isVBox(parent) ? "⬇ Down" : "➡ Right"); + } + else + { + upButton->setEnabled(false); + downButton->setEnabled(false); + } + + // TODO: Enable the [Add] menu button only when a widget can be added + // inside the current widget (i.e. it is a container). Check the widget's + // child manager wheter it is YSingleWidgetChildManager or a YWidgetChildrenRejector. + + // Disable the [Delete] button when for the top level widget (YDialog) + // TODO: disable it for the YQWizardButtons (Next, Back, ...), they cannot be + // removed from the dialog. + deleteButton->setEnabled(parent); +} + +/** + * Edit widget property + * @param widget selected widget + * @param property property name + */ +void YDialogSpyPrivate::editWidget(YWidget *widget, const std::string &property) +{ + // redraw the target dialog + targetDialog->recalcLayout(); + + if (!widget->propertySet().contains(property)) return; + + YPropertyEditor editor(widget); + editor.edit(property); +} diff --git a/src/YDialogSpy.h b/src/YDialogSpy.h new file mode 100644 index 0000000..9cfaa68 --- /dev/null +++ b/src/YDialogSpy.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDialogSpy.h + + Author: Stefan Hundhammer + +/-*/ + + +#ifndef YDialogSpy_h +#define YDialogSpy_h + +#include "ImplPtr.h" + +class YWidget; +class YDialog; +class YDialogSpyPrivate; + + +/** + * An interactive dialog debugger: Show the structure and content of a dialog + * and its widgets. + * + * This can be invoked by special key combinations: + * Ctrl-Alt-Shift-Y in the Qt UI + **/ +class YDialogSpy +{ +public: + /** + * Show a YDialogSpy for the specified dialog. 0 means "use the topmost + * dialog". + * This will return only when the user closes the YDialogSpy dialog. + **/ + static void showDialogSpy( YDialog * dialog = 0 ); + + /** + * Show the "Properties" sub-window. + **/ + void showProperties(); + + /** + * Hide the "Properties" sub-window. + **/ + void hideProperties(); + + /** + * Return 'true' if the "Properties" sub-window is currently shown, + * 'false' if not. + **/ + bool propertiesShown() const; + +protected: + /** + * Constructor: Create a YDialogSpy for the specified dialog. 0 means "use + * the topmost dialog". + * + * In most cases it is more useful to use the static showDialogSpy() method + * rather than create this dialog directly. + **/ + YDialogSpy( YDialog * dialog = 0 ); + + /** + * Destructor. + **/ + virtual ~YDialogSpy(); + + /** + * Execute the event loop. This will only return when the user closes the + * YDialogSpy dialog. + **/ + void exec(); + + /** + * Show the properties of the specified widget if the "Properties" + * sub-window is currently shown. + **/ + void showProperties( YWidget * widget ); + +private: + + ImplPtr priv; +}; + + +#endif // YDialogSpy_h diff --git a/src/YDownloadProgress.cc b/src/YDownloadProgress.cc new file mode 100644 index 0000000..66361ad --- /dev/null +++ b/src/YDownloadProgress.cc @@ -0,0 +1,198 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDownloadProgress.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YDownloadProgress.h" + + + +struct YDownloadProgressPrivate +{ + YDownloadProgressPrivate( const std::string & label, + const std::string & filename, + YFileSize_t expectedSize ) + : label( label ) + , filename( filename ) + , expectedSize( expectedSize ) + {} + + std::string label; + std::string filename; + YFileSize_t expectedSize; +}; + + +YDownloadProgress::YDownloadProgress( YWidget * parent, + const std::string & label, + const std::string & filename, + YFileSize_t expectedSize ) + : YWidget( parent ) + , priv( new YDownloadProgressPrivate( label, filename, expectedSize ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setStretchable( YD_VERT, false ); +} + + +YDownloadProgress::~YDownloadProgress() +{ + // NOP +} + + +std::string +YDownloadProgress::label() const +{ + return priv->label; +} + + +void +YDownloadProgress::setLabel( const std::string & label ) +{ + priv->label = label; +} + + +std::string +YDownloadProgress::filename() const +{ + return priv->filename; +} + + +void +YDownloadProgress::setFilename( const std::string & filename ) +{ + priv->filename = filename; +} + + +YFileSize_t +YDownloadProgress::expectedSize() const +{ + return priv->expectedSize; +} + + +void +YDownloadProgress::setExpectedSize( YFileSize_t newSize ) +{ + priv->expectedSize = newSize; +} + + +int +YDownloadProgress::currentPercent() const +{ + if ( priv->expectedSize == 0 ) // Avoid division by zero + return 0; + + YFileSize_t currentSize = currentFileSize(); + + if ( currentSize >= priv->expectedSize ) + return 100; + else + return (int) ( (100 * currentSize ) / priv->expectedSize ); +} + + +YFileSize_t +YDownloadProgress::currentFileSize() const +{ + struct stat stat_info; + + if ( stat( priv->filename.c_str(), & stat_info ) == 0 ) + return (YFileSize_t) stat_info.st_size; + else + return 0; +} + + +const YPropertySet & +YDownloadProgress::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Label text above the progress bar + * @property std::string Filename name of the file that is monitored + * @property integer ExpectedSize expected size of the file in bytes + * @property integer CurrentSize current size of the file in bytes (read-only!) + * @property integer Value current percent of the download (read-only!) + */ + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Filename, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_ExpectedSize, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentSize, YIntegerProperty, true ) ); // read-only + propSet.add( YProperty( YUIProperty_Value, YIntegerProperty, true ) ); // read-only + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YDownloadProgress::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Label ) setLabel ( val.stringVal() ); + if ( propertyName == YUIProperty_Filename ) setFilename ( val.stringVal() ); + if ( propertyName == YUIProperty_ExpectedSize ) setExpectedSize( val.integerVal() ); + else + { + YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special handling necessary +} + + +YPropertyValue +YDownloadProgress::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + if ( propertyName == YUIProperty_Filename ) return YPropertyValue( filename() ); + if ( propertyName == YUIProperty_ExpectedSize ) return YPropertyValue( expectedSize() ); + if ( propertyName == YUIProperty_CurrentSize ) return YPropertyValue( currentFileSize()); + if ( propertyName == YUIProperty_Value ) return YPropertyValue( currentPercent() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YDownloadProgress.h b/src/YDownloadProgress.h new file mode 100644 index 0000000..c47ec4f --- /dev/null +++ b/src/YDownloadProgress.h @@ -0,0 +1,159 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDownloadProgress.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YDownloadProgress_h +#define YDownloadProgress_h + +#include "YWidget.h" + + +class YDownloadProgressPrivate; + +/** + * DownloadProgress: A progress bar that monitors downloading a file by + * repeatedly polling its size up to its expected size. + **/ +class YDownloadProgress : public YWidget +{ +protected: + /** + * Constructor. + * + * 'label' is the label above the progress bar. + * + * 'filename' is the name (with path) of the file being monitored. + * + * 'expectedSize' is the expected size of the file in bytes. + **/ + YDownloadProgress( YWidget * parent, + const std::string & label, + const std::string & filename, + YFileSize_t expectedSize ); +public: + /** + * Destructor. + **/ + virtual ~YDownloadProgress(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YDownloadProgress"; } + + /** + * Get the label (the text above the progress bar). + **/ + std::string label() const; + + /** + * Set the label (the text above the progress bar). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Return the name of the file that is being monitored. + **/ + std::string filename() const; + + /** + * Set the name of a new file to monitor. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setFilename( const std::string & filename ); + + /** + * Return the expected file size. + **/ + YFileSize_t expectedSize() const; + + /** + * Set the expected file size. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setExpectedSize( YFileSize_t newSize ); + + /** + * Return the current size of the file that is being downloaded + * or 0 if this file doesn't exist (yet). + * + * This default implementation returns the 'st_size' field of a stat() + * system call on the file. This should be useful for most implementations. + **/ + virtual YFileSize_t currentFileSize() const; + + /** + * Return the percentage (0..100) of the file being downloaded so far. + **/ + int currentPercent() const; + + /** + * Alias for currentPercent(). + **/ + int value() const { return currentPercent(); } + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + +private: + + ImplPtr priv; +}; + + +#endif // YDownloadProgress_h diff --git a/src/YDumbTab.cc b/src/YDumbTab.cc new file mode 100644 index 0000000..8752137 --- /dev/null +++ b/src/YDumbTab.cc @@ -0,0 +1,150 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDumbTab.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YDumbTab.h" +#include "YShortcut.h" + + +struct YDumbTabPrivate +{ + YDumbTabPrivate() + {} + + bool dummy; +}; + + + + +YDumbTab::YDumbTab( YWidget * parent ) + : YSelectionWidget( parent, + "", // label + true ) // enforceSingleSelection + , priv( new YDumbTabPrivate ) +{ + YUI_CHECK_NEW( priv ); + setChildrenManager( new YSingleWidgetChildManager( this ) ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YDumbTab::~YDumbTab() +{ + // NOP +} + + +void +YDumbTab::addItem( YItem * item ) +{ + YSelectionWidget::addItem( item ); +} + + +bool +YDumbTab::stretchable( YUIDimension dim ) const +{ + if ( hasChildren() ) + return firstChild()->stretchable( dim ); + else + return YWidget::stretchable( dim ); +} + + +std::string +YDumbTab::debugLabel() const +{ + std::string str = widgetClass(); + + for ( YItemConstIterator it = itemsBegin(); + it != itemsEnd(); + ++it ) + { + str += " [" + (*it)->label() + "]"; + } + + return str; +} + + + +const YPropertySet & +YDumbTab::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property itemID Value The currently selected item (tab page) + * @property itemID CurrentItem The currently selected item (tab page) + * @property itemList Items All items (all tab pages) + */ + propSet.add( YProperty( YUIProperty_Value, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentItem, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YDumbTab::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) return false; // Needs special handling + else if ( propertyName == YUIProperty_CurrentItem ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YDumbTab::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_CurrentItem ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YDumbTab.h b/src/YDumbTab.h new file mode 100644 index 0000000..aec17a3 --- /dev/null +++ b/src/YDumbTab.h @@ -0,0 +1,157 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YDumbTab.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YDumbTab_h +#define YDumbTab_h + +#include "YSelectionWidget.h" + +class YDumbTabPrivate; + +/** + * DumbTab: A very simple tab widget that can display and switch between a + * number of tabs, but will only deliver the "user clicked on tab " event very + * much like a PushButton does. Actually exchanging the content of the tab is + * left to the application. + * + * DumbTab accepts a single child widget. + **/ +class YDumbTab : public YSelectionWidget +{ +protected: + /** + * Constructor. + **/ + YDumbTab( YWidget * parent ); + +public: + /** + * Destructor. + **/ + virtual ~YDumbTab(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YDumbTab"; } + + /** + * Add an item (a tab page). + * + * Reimplemented from YSelectionWidget. + * + * Derived classes can overwrite this function, but they should call this + * base class function in the new implementation. + **/ + virtual void addItem( YItem * item ); + + /** + * Notification that any shortcut of any item was changed by the shortcut + * conflict manager. + * + * Derived classes should reimplement this. + **/ + virtual void shortcutChanged() {} + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property set upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * Notice that since YDumbTab has one shortcut for each tab page (for each + * item), this is not meaningful for this widget class. + * + * Check YItemShortcut in YShortcut.{cc,h} for more details. + * + * Reimplemented from YSelectionWidget. + **/ + virtual std::string shortcutString() const { return ""; } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * Since YDumbTab doesn't have a shortcut for the widget itself (only for + * the tab pages, i.e. the items), this will simply trigger a + * shortcutChanged() notification. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void setShortcutString( const std::string & str ) { shortcutChanged(); } + + /** + * Returns 'true' if this widget is stretchable in the specified dimension. + * In this case, the stretchability of the single child is returned. + * + * Reimplemented from YWidget. + **/ + virtual bool stretchable( YUIDimension dim ) const; + + /** + * Descriptive label for debugging. Derived from this widget's only child + * (if there is one). + **/ + virtual std::string debugLabel() const; + +private: + + // Disable unwanted base class methods + std::string label() const; + virtual void setLabel( const std::string & newLabel ) {}; + + + ImplPtr priv; +}; + + +#endif // YDumbTab_h diff --git a/src/YEmpty.cc b/src/YEmpty.cc new file mode 100644 index 0000000..f5362c9 --- /dev/null +++ b/src/YEmpty.cc @@ -0,0 +1,59 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEmpty.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YEmpty.h" + +struct YEmptyPrivate +{ + bool dummy; +}; + + + + +YEmpty::YEmpty( YWidget * parent ) + :YWidget( parent ) + , priv( new YEmptyPrivate ) +{ + YUI_CHECK_NEW( priv ); +} + + +YEmpty::~YEmpty() +{ + // NOP +} + + +int YEmpty::preferredWidth() +{ + return 0; +} + + +int YEmpty::preferredHeight() +{ + return 0; +} diff --git a/src/YEmpty.h b/src/YEmpty.h new file mode 100644 index 0000000..9a3cb36 --- /dev/null +++ b/src/YEmpty.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEmpty.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YEmpty_h +#define YEmpty_h + +#include "YWidget.h" +#include "ImplPtr.h" + + +class YEmptyPrivate; + +/** + * A widget with zero size, useful as a placeholder. + **/ +class YEmpty : public YWidget +{ +protected: + /** + * Constructor. + **/ + YEmpty( YWidget * parent ); + +public: + /** + * Destructor. + **/ + virtual ~YEmpty(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YEmpty"; } + + /** + * Preferred width of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredWidth(); + + /** + * Preferred height of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredHeight(); + +private: + + ImplPtr priv; +}; + + +#endif // YEmpty_h diff --git a/src/YEnvVar.cc b/src/YEnvVar.cc new file mode 100644 index 0000000..a0caf53 --- /dev/null +++ b/src/YEnvVar.cc @@ -0,0 +1,114 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEnvVar.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include // getenv() +#include // strcmp(), strcasecmp() +#include // tolower() + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include + + +YEnvVar::YEnvVar( const std::string & name ) + : _name( name ) + , _isSet( false ) +{ + if ( ! _name.empty() ) + { + const char * val = getenv( _name.c_str() ); + + if ( val ) + { + _isSet = true; + _value = val; + } + } +} + + +bool +YEnvVar::isEqual( const std::string & str, bool caseSensitive ) const +{ + if ( ! _isSet ) + return false; + + if ( caseSensitive ) + return strcmp( _value.c_str(), str.c_str() ) == 0; + else + return strcasecmp( _value.c_str(), str.c_str() ) == 0; +} + +bool +YEnvVar::contains( const std::string & str, bool caseSensitive ) const +{ + if ( ! _isSet ) + return false; + + if ( caseSensitive ) + { + return _value.find( str ) != std::string::npos; + } + else + { + return tolower( _value ).find( tolower( str ) ) != std::string::npos; + } +} + + +std::string tolower( const std::string & str ) +{ + std::string lowStr; + lowStr.reserve( str.size() ); + + for ( std::string::const_iterator it = str.begin(); + it != str.end(); + ++it ) + { + lowStr += ::tolower( *it ); + } + + return lowStr; +} + + +std::ostream & +operator<<( std::ostream & stream, const YEnvVar env ) +{ + if ( env.name().empty() ) + { + stream << ""; + } + else + { + if ( env.isSet() ) + stream << "$" << env.name() << "=\"" << env.value() << "\""; + else + stream << "$" << env.name() << ": "; + } + + return stream; +} diff --git a/src/YEnvVar.h b/src/YEnvVar.h new file mode 100644 index 0000000..fa24535 --- /dev/null +++ b/src/YEnvVar.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEnvVar.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YEnvVar_h +#define YEnvVar_h + +#include +#include + + + +/** + * Helper class to represent an environment variable and its value. + **/ +class YEnvVar +{ +public: + /** + * Constructor: + * Retrieve the environment variable 'name' and store the value + * (unless 'name' is empty). + **/ + YEnvVar( const std::string & name = std::string() ); + + /** + * Return the name of the environment variable. + **/ + std::string name() const { return _name; } + + /** + * Return 'true' if the environment variable is set. + **/ + bool isSet() const { return _isSet; } + + /** + * Return the value of the environment variable. + **/ + std::string value() const { return _value; } + + /** + * Return 'true' if the environment variable is set and the value is + * 'str'. + **/ + bool isEqual( const std::string & str, bool caseSensitive = false ) const; + + /** + * Case-insensitive comparison (shortcut for isEqual() ): + * Return 'true' if the environment variable is set and the value is + * 'str'. + **/ + bool operator==( const std::string & str ) const + { return isEqual( str ); } + + /** + * Return 'true' if the environment variable is set and the value contains + * 'str'. + **/ + bool contains( const std::string & str, bool caseSensitive = false ) const; + + +private: + + std::string _name; + std::string _value; + bool _isSet; +}; + + +/** + * Stream output for YEnvVar + **/ +std::ostream & operator<<( std::ostream & stream, const YEnvVar env ); + + +/** + * Return 'str' converted to lower case. + **/ +std::string tolower( const std::string & str ); + + +#endif // YEnvVar_h diff --git a/src/YEvent.cc b/src/YEvent.cc new file mode 100644 index 0000000..abb4bdf --- /dev/null +++ b/src/YEvent.cc @@ -0,0 +1,147 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEvent.cc + + Author: Stefan Hundhammer + +/-*/ + + + +#define YUILogComponent "ui-events" +#include "YUILog.h" + +#include "YWidget.h" +#include "YEvent.h" +#include "YDialog.h" + + +unsigned long YEvent::_nextSerial = 0; + + +YEvent::YEvent( EventType eventType ) + : _eventType( eventType ) +{ + _dialog = YDialog::currentDialog( false ); // don't throw + _serial = _nextSerial++; +} + + +YEvent::~YEvent() +{ + invalidate(); +} + + +bool +YEvent::isValid() const +{ + return _eventType != InvalidEvent; +} + + +void +YEvent::invalidate() +{ + _eventType = InvalidEvent; +} + + +const char * +YEvent::toString( EventType eventType ) +{ + switch ( eventType ) + { + case NoEvent: return "NoEvent"; + case UnknownEvent: return "UnknownEvent"; + case WidgetEvent: return "WidgetEvent"; + case MenuEvent: return "MenuEvent"; + case KeyEvent: return "KeyEvent"; + case CancelEvent: return "CancelEvent"; + case TimeoutEvent: return "TimeoutEvent"; + case DebugEvent: return "DebugEvent"; + case InvalidEvent: return "InvalidEvent"; + + // Intentionally omitting "default" branch so the compiler can + // detect unhandled enums + } + + return ""; +} + + +const char * +YEvent::toString( EventReason reason ) +{ + switch ( reason ) + { + case UnknownReason: return "Unknown"; + case Activated: return "Activated"; + case SelectionChanged: return "SelectionChanged"; + case ValueChanged: return "ValueChanged"; + case ContextMenuActivated: return "ContextMenuActivated"; + + // Intentionally omitting "default" branch so the compiler can + // detect unhandled enums + } + + return ""; +} + + + + +YWidgetEvent::YWidgetEvent( YWidget * widget, + EventReason reason, + EventType eventType ) + : YEvent( eventType ) + , _widget( widget ) + , _reason( reason ) +{ + if ( widget ) + setDialog( widget->findDialog() ); +} + + + +YKeyEvent::YKeyEvent( const std::string & keySymbol, + YWidget * focusWidget ) + : YEvent( KeyEvent ) + , _keySymbol( keySymbol ) + , _focusWidget( focusWidget ) +{ +} + + + +std::ostream & +operator<<( std::ostream & stream, const YEvent * event ) +{ + if ( event ) + { + stream << YEvent::toString( event->eventType() ) + << " at " << std::hex << (void *) event << std::dec; + } + else + { + stream << ""; + } + + return stream; +} diff --git a/src/YEvent.h b/src/YEvent.h new file mode 100644 index 0000000..192b339 --- /dev/null +++ b/src/YEvent.h @@ -0,0 +1,365 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEvent.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YEvent_h +#define YEvent_h + + +#include +#include +#include "YDialog.h" +#include "YSimpleEventHandler.h" + +class YWidget; +class YItem; +class YDialog; + + +/** + * Abstract base class for events to be returned upon UI::UserInput() + * and related functions. + **/ +class YEvent +{ +public: + + enum EventType + { + NoEvent = 0, + UnknownEvent, + WidgetEvent, + MenuEvent, + KeyEvent, + CancelEvent, + TimeoutEvent, + DebugEvent, + InvalidEvent = 0x4242 + }; + + + enum EventReason + { + UnknownReason = 0, + Activated, + SelectionChanged, + ValueChanged, + ContextMenuActivated + }; + + + /** + * Constructor. + **/ + YEvent( EventType eventType = UnknownEvent ); + + /** + * Returns the event type. + **/ + EventType eventType() const { return _eventType; } + + /** + * Returns the unique serial no. of this event. + * This is mainly useful for debugging. + **/ + unsigned long serial() const { return _serial; } + + /** + * Returns the widget that caused this event or 0 if there is none. + * + * This default implementation always returns 0. + * Subclasses that actually return widgets should overwrite this method. + **/ + virtual YWidget * widget() const { return 0; } + + /** + * Return the YItem that corresponds to this event or 0 if there is none. + * + * This default implementation always returns 0. + * Subclasses that actually return items should overwrite this method. + **/ + virtual YItem * item() const { return 0; } + + /** + * Return the dialog this event belongs to or 0 if no dialog was set yet. + **/ + YDialog * dialog() const { return _dialog; } + + /** + * Check if this event is valid. Events become invalid in the destructor. + **/ + bool isValid() const; + + /** + * Returns the character representation of an event type. + **/ + static const char * toString( EventType eventType ); + + /** + * Returns the character representation of an event reason. + **/ + static const char * toString( EventReason reason ); + + +protected: + + /** + * Set the dialog this event belongs to. + **/ + void setDialog( YDialog * dia ) { _dialog = dia; } + + /** + * Protected destructor - events can only be deleted via + * YDialog::deleteEvent(). The associated dialog will take care of this + * event and delete it when appropriate. + * + * This desctructor is virtual to force a polymorph object + * so dynamic_cast<> can be used. + **/ + virtual ~YEvent(); + + /** + * Mark this event as invalid. This cannot be undone. + **/ + void invalidate(); + +private: + + friend void YDialog::deleteEvent( YEvent * event ); + friend void YSimpleEventHandler::deleteEvent( YEvent * event ); + + + // + // Data members + // + + EventType _eventType; + unsigned long _serial; + YDialog * _dialog; + + static unsigned long _nextSerial; +}; + + + +class YWidgetEvent: public YEvent +{ +public: + + /** + * Constructor. + **/ + YWidgetEvent( YWidget * widget = 0, + EventReason reason = Activated, + EventType eventType = WidgetEvent ); + + /** + * Returns the widget that caused this event. + * Reimplemented from YEvent. + **/ + virtual YWidget * widget() const { return _widget; } + + /** + * Returns the reason for this event. This very much like an event sub-type. + **/ + EventReason reason() const { return _reason; } + +protected: + + /** + * Protected destructor - events can only be deleted via + * YDialog::deleteEvent(). The associated dialog will take care of this + * event and delete it when appropriate. + **/ + virtual ~YWidgetEvent() {} + + + // + // Data members + // + + YWidget * _widget; + EventReason _reason; +}; + + +class YKeyEvent: public YEvent +{ +public: + + /** + * Constructor. + * + * Create a key event with a specified key symbol (a text describing the + * key, such as "CursorLeft", "F1", etc.) and optionally the widget that + * currently has the keyboard focus. + **/ + YKeyEvent( const std::string & keySymbol, + YWidget * focusWidget = 0 ); + + /** + * Returns the key symbol - a text describing the + * key, such as "CursorLeft", "F1", "a", "A", etc. + **/ + std::string keySymbol() const { return _keySymbol; } + + /** + * Returns the widget that currently has the keyboard focus. + * + * This might be 0 if no widget has the focus or if the creator of + * this event could not obtain that information. + **/ + YWidget * focusWidget() const { return _focusWidget; } + +protected: + + /** + * Protected destructor - events can only be deleted via + * YDialog::deleteEvent(). The associated dialog will take care of this + * event and delete it when appropriate. + **/ + virtual ~YKeyEvent() {} + + + // + // Data members + // + + std::string _keySymbol; + YWidget * _focusWidget; +}; + + +/** + * Event to be returned upon menu selection. + **/ +class YMenuEvent: public YEvent +{ +public: + + YMenuEvent( YItem * item ) + : YEvent( MenuEvent ) + , _item( item ) + {} + + YMenuEvent( const char * id ) : YEvent( MenuEvent ), _item(0), _id( id ) {} + YMenuEvent( const std::string & id ) : YEvent( MenuEvent ), _item(0), _id( id ) {} + + /** + * Return the YItem that corresponds to this event or 0 if the event was + * constructed with a string ID. + * + * Reimplemented from YEvent. + **/ + virtual YItem * item() const { return _item; } + + /** + * Return the string ID of this event. This will be an empty string if the + * event was constructed with a YItem. + **/ + std::string id() const { return _id; } + +protected: + + /** + * Protected destructor - events can only be deleted via + * YDialog::deleteEvent(). The associated dialog will take care of this + * event and delete it when appropriate. + **/ + virtual ~YMenuEvent() {} + + + // + // Data members + // + + YItem * _item; + std::string _id; +}; + + +/** + * Event to be returned upon closing a dialog with the window manager close + * button (or Alt-F4) + **/ +class YCancelEvent: public YEvent +{ +public: + + YCancelEvent() : YEvent( CancelEvent ) {} + + +protected: + /** + * Protected destructor - events can only be deleted via + * YDialog::deleteEvent(). The associated dialog will take care of this + * event and delete it when appropriate. + **/ + virtual ~YCancelEvent() {} +}; + + +/** + * Event to be returned upon closing a dialog with the window manager close + * button (or Alt-F4) + **/ +class YDebugEvent: public YEvent +{ +public: + + YDebugEvent() : YEvent( DebugEvent ) {} + +protected: + /** + * Protected destructor - events can only be deleted via + * YDialog::deleteEvent(). The associated dialog will take care of this + * event and delete it when appropriate. + **/ + virtual ~YDebugEvent() {} +}; + + +/** + * Event to be returned upon timeout + * (i.e. no event available in the specified timeout) + **/ +class YTimeoutEvent: public YEvent +{ +public: + + YTimeoutEvent() : YEvent( TimeoutEvent ) {} + +protected: + /** + * Protected destructor - events can only be deleted via + * YDialog::deleteEvent(). The associated dialog will take care of this + * event and delete it when appropriate. + **/ + virtual ~YTimeoutEvent() {} +}; + + +std::ostream & operator<<( std::ostream & stream, const YEvent * event ); + + +#endif // YEvent_h diff --git a/src/YEventFilter.cc b/src/YEventFilter.cc new file mode 100644 index 0000000..ac163e8 --- /dev/null +++ b/src/YEventFilter.cc @@ -0,0 +1,66 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEventFilter.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YEventFilter.h" +#include "YEvent.h" +#include "YDialog.h" +#include "YUIException.h" + + +struct YEventFilterPrivate +{ + YEventFilterPrivate( YDialog * dialog ) + : dialog( dialog ) + {} + + YDialog * dialog; +}; + + + + +YEventFilter::YEventFilter( YDialog * dialog ) + : priv( new YEventFilterPrivate( dialog ) ) +{ + YUI_CHECK_NEW( priv ); + + if ( ! dialog ) + priv->dialog = YDialog::currentDialog(); // throw if no dialog + + priv->dialog->addEventFilter( this ); +} + + +YEventFilter::~YEventFilter() +{ + priv->dialog->removeEventFilter( this ); +} + + +YDialog * +YEventFilter::dialog() const +{ + return priv->dialog; +} diff --git a/src/YEventFilter.h b/src/YEventFilter.h new file mode 100644 index 0000000..3dc1803 --- /dev/null +++ b/src/YEventFilter.h @@ -0,0 +1,120 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEventFilter.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YEventFilter_h +#define YEventFilter_h + + +#include "ImplPtr.h" + + +class YEvent; +class YDialog; + +class YEventFilterPrivate; + + +/** + * Abstract base class to filter events. + * + * This class can be used to examine events just before they are delivered to + * the application. This is most useful for higher-level widgets or for + * libraries that need to react to certain events and either consume them, have + * them delivered unchanged to the application, or exchange an event with + * another one. + * + * A YEventFilter belongs to one specific dialog. Each dialog can have any + * number of event filters. Each of those event filters is called (its + * YEventFilter::filter() method) for each event inside + * YDialog::waitForEvent(). The order in which event filters are called is + * undefined. + * + * YEventFilter objects should be created with 'new' (on the heap). Since an + * YEventFilter registers itself with its dialog, the dialog will delete it in + * its destructor if it still exists after all child widgets are deleted. + * + * Thus, it is safe to store a pointer to an YEventFilter until the + * corresponding dialog is deleted. After that, the pointer becomes invalid. + * + * See YHelpButtonHandler in YDialog.cc for an example. + **/ +class YEventFilter +{ +protected: + /** + * Constructor. + * + * This registers the event filter with the specified dialog. The dialog + * assumes ownership of this object and will delete it in its destructor + * (unless this object is destroyed before that time). + * + * If 'dialog' is 0, YDialog::currentDialog() is used (which can throw a + * YUINoDialogException if there is no dialog). + **/ + YEventFilter( YDialog * dialog = 0 ); + +public: + /** + * Destructor. + * + * This will unregister this object with its dialog. + **/ + virtual ~YEventFilter(); + + /** + * The heart of the matter: The event filter function. + * Derived classes are required to implement this. + * + * This method can inspect the event it receives. Hint: event->widget() + * is typically the most interesting information. + * + * This method can react on individual events and + * + * - consume the event (i.e., return 0) + * - pass the event through unchanged (simply return the event) + * - create a new event (typically based on data in the received event). + * + * If 0 or a new event (another value than 'event') is returned, the old + * event is deleted. If a value different from 'event' or 0 is returned, + * that value is assumed to be a pointer to a newly created event. The + * dialog will assume ownership of that event and delete it when + * appropriate. + * + * Note: Never delete 'event' in this method! Return 0 or a new event + * instead; the caller will take care of deleting the old event. + **/ + virtual YEvent * filter( YEvent * event ) = 0; + + /** + * Return the dialog this event filter belongs to. + **/ + YDialog * dialog() const; + +private: + + ImplPtr priv; +}; + + +#endif // YEventFilter_h diff --git a/src/YExternalWidgetFactory.h b/src/YExternalWidgetFactory.h new file mode 100644 index 0000000..7c58575 --- /dev/null +++ b/src/YExternalWidgetFactory.h @@ -0,0 +1,51 @@ +/* + Copyright (C) 2013 Angelo Naselli + + This file is part of libyui project + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef YExternalWidgetFactory_h +#define YExternalWidgetFactory_h + +/** + * Abstract widget factory for mandatory widgets. + * Use YOptionalWidgetFactory for optional ("special") widgets. + * YExternalWidgetFactory is used for external widgets, e.g. user defined plugin. + * + * Refer to the respective widget's documentation (in the header file) for + * documentation about the function parameters. + **/ +class YExternalWidgetFactory +{ +protected: + + friend class YUI; + friend class YExternalWidgets; + + /** + * Constructor. + * + * Use YExternalWidgets::widgetExtensionFactory() to get the singleton for this class. + **/ + YExternalWidgetFactory() {} + + /** + * Destructor. + **/ + virtual ~YExternalWidgetFactory() {} + +}; // class YExternalWidgetFactory + +#endif // YExternalWidgetFactory_h \ No newline at end of file diff --git a/src/YExternalWidgets.cc b/src/YExternalWidgets.cc new file mode 100644 index 0000000..856ef99 --- /dev/null +++ b/src/YExternalWidgets.cc @@ -0,0 +1,131 @@ +/* + Copyright (C) 2013 Angelo Naselli + + This file is part of libyui project + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ +#define YUILogComponent "ew" +#include "YUILog.h" + +#include "YUI.h" +#include "YUILoader.h" +#include "YUIException.h" +#include "YExternalWidgets.h" +#include "YExternalWidgetFactory.h" + +#include +#include + +std::map YExternalWidgets::_externalWidgets; + +YExternalWidgets::YExternalWidgets(const std::string& name) : _name(name), _factory(0) +{ + if (!YUI::ui()) + YUI_THROW( YUIException( "UI must be initialized first" ) ); + + yuiMilestone() << "Creating Libyui External Widgets object" << std::endl; + + std::pair::iterator, bool> ret; + ret = _externalWidgets.insert ( std::pair(_name, this)); + if (ret.second==false) { + std::string errorString = _name; + errorString.append(" already created"); + YUI_THROW( YUIException( errorString ) ); + } +} + +YExternalWidgets::~YExternalWidgets() +{ + delete _factory; + + _externalWidgets.erase(_name); +} + +YExternalWidgets* YExternalWidgets::externalWidgets(const std::string& name) +{ + std::map::iterator it; + + if (!YUI::ui()) + YUI_THROW( YUIException( "UI must be initialized first" ) ); + + it = _externalWidgets.find(name); + if (it == _externalWidgets.end()) + { + YUILoader::loadExternalWidgets(name); + } + + return _externalWidgets[name]; +} + +YExternalWidgetFactory* YExternalWidgets::externalWidgetFactory(const std::string& name) +{ + return YExternalWidgets::externalWidgets(name)->externalWidgetFactory(); +} + +YExternalWidgetFactory* YExternalWidgets::externalWidgetFactory() +{ + if (!YUI::ui()) + YUI_THROW( YUIException( "UI must be initialized first" ) ); + + if ( !_factory ) + _factory = this->createExternalWidgetFactory(); + + YUI_CHECK_PTR( _factory ); + + return _factory; +} + + +/** + * Helper class to make sure the EW is properly shut down. + **/ +class YExternalWidgetsTerminator +{ +public: + YExternalWidgetsTerminator() {} + + /** + * Destructor. + * + * If there still is a EW, it will be deleted. + * If there is none, this will do nothing. + **/ + ~YExternalWidgetsTerminator(); +}; + + +YExternalWidgetsTerminator::~YExternalWidgetsTerminator() +{ + // Let's copy map to avoid content deletion when removing ExternalWidgets objects + std::map ew = YExternalWidgets::_externalWidgets; + std::map::iterator it; + + for (it= ew.begin(); it != ew.end(); it++) + { + yuiMilestone() << "Shutting down " << it->first << " External Widgets" << std::endl; + delete it->second; + } +} + + +/** + * Static YExternalWidgetsTerminator instance: It will make sure the EW is deleted in its + * global destructor. If the EW is already destroyed, it will do nothing. If + * there still is a EW object, it will be deleted. + * + * This is particularly important for the NCurses EW so the terminal settings + * are properly restored. + **/ +static YExternalWidgetsTerminator weTerminator; + diff --git a/src/YExternalWidgets.h b/src/YExternalWidgets.h new file mode 100644 index 0000000..88117ec --- /dev/null +++ b/src/YExternalWidgets.h @@ -0,0 +1,104 @@ +/* + Copyright (C) 2013 Angelo Naselli + + This file is part of libyui project + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef YExternalWidgets_h +#define YExternalWidgets_h +#include +#include + +class YExternalWidgetFactory; + +/** + * Abstract base class of a libYUI Widget Extension interface. + **/ +class YExternalWidgets +{ + friend class YExternalWidgetsTerminator; + +protected: + /** + * Constructor. + * 'name' is the plugin name + * + * throws a YUIException if the plugin 'name' has been alread created + **/ + YExternalWidgets( const std::string& name ); + +public: + + /** + * Destructor. + **/ + virtual ~YExternalWidgets(); + + + /** + * Access the global YUI external widgets. + * 'name' is the plugin name + * + * if plugin 'name' has not been explicitally loaded by YUILoader::loadExternalWidgets + * externalWidgets try loading it (exactly as YUI::ui does) with default function symbol + * to be executed (see YUILoader::loadExternalWidgets for explanation) + **/ + static YExternalWidgets * externalWidgets(const std::string& name); + + /** + * Return the external widget factory that provides all the createXY() methods for + * user defined widgets. + * + * This will create the factory upon the first call and return a pointer to + * the one and only (singleton) factory upon each subsequent call. + * This may throw exceptions if the factory cannot be created. + * + * It is up to user extend YExternalWidgetFactory to add createXY() methods in + * his/her implementation. So once YExternalWidgetFactory is extended with + * all the createXY() methods, three sub-plugins must be defined one for each + * supported graphical environment, e.g. Gtk, ncurses and QT, following the + * libyui implementation rules. + * + * For instance an external widgets plugin called yui-foo that needs Gtk, ncurses + * and QT specialization will require also yui-foo-gtk, yui-foo-ncurses and + * yui-foo-qt plugin implementation. + * + **/ + YExternalWidgetFactory * externalWidgetFactory(); + static YExternalWidgetFactory * externalWidgetFactory(const std::string& name); + +protected: + + /** + * Create the external widgets factory that provides all the createXY() methods for + * + * Derived classes are required to implement this. Usually createXY() is virtual, + * real implementation is demanded to derived classes that implement Gtk, ncurses and QT + * specialization. + **/ + virtual YExternalWidgetFactory * createExternalWidgetFactory() = 0; + +private: + /** Externale widgets plugin name */ + std::string _name; + + /** Externale widget factory */ + YExternalWidgetFactory* _factory; + + /** plugin instances */ + static std::map _externalWidgets; +}; + +#endif // YExternalWidgets_h diff --git a/src/YFrame.cc b/src/YFrame.cc new file mode 100644 index 0000000..3516bc0 --- /dev/null +++ b/src/YFrame.cc @@ -0,0 +1,115 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YFrame.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YFrame.h" +#include "YShortcut.h" + +struct YFramePrivate +{ + YFramePrivate( const std::string & frameLabel ) + : label( frameLabel ) + {} + + std::string label; +}; + + + + +YFrame::YFrame( YWidget * parent, const std::string & label ) + : YSingleChildContainerWidget( parent ) + , priv( new YFramePrivate( YShortcut::cleanShortcutString( label ) ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YFrame::~YFrame() +{ + // NOP +} + + +void YFrame::setLabel( const std::string & newLabel ) +{ + priv->label = YShortcut::cleanShortcutString( newLabel ); +} + + +std::string YFrame::label() const +{ + return priv->label; +} + + +const YPropertySet & +YFrame::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Label the text on the frame + */ + + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YFrame::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YFrame::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YFrame.h b/src/YFrame.h new file mode 100644 index 0000000..111e8ec --- /dev/null +++ b/src/YFrame.h @@ -0,0 +1,111 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YFrame.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YFrame_h +#define YFrame_h + +#include +#include "YSingleChildContainerWidget.h" +#include "ImplPtr.h" + +class YFramePrivate; + + +/** + * A labeled framed container. + **/ +class YFrame : public YSingleChildContainerWidget +{ +protected: + /** + * Constructor. + **/ + YFrame( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YFrame(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YFrame"; } + + /** + * Change the frame label. + * + * Derived classes should overwrite this, but call this base class function + * in the overwritten function. + **/ + virtual void setLabel( const std::string & newLabel ); + + /** + * Get the current frame label. + **/ + std::string label() const; + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property set upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + +private: + + ImplPtr priv; +}; + + +#endif // YFrame_h diff --git a/src/YGraph.cc b/src/YGraph.cc new file mode 100644 index 0000000..cde3bb9 --- /dev/null +++ b/src/YGraph.cc @@ -0,0 +1,162 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YGraph.cc + + Author: Arvin Schnell + +/-*/ + + +#define YUILogComponent "ui-graph" +#include "YUILog.h" + +#include "YGraph.h" + + +struct YGraphPrivate +{ + YGraphPrivate( std::string filename, std::string layoutAlgorithm ) + : filename( filename ), + layoutAlgorithm( layoutAlgorithm ) + {} + + std::string filename; + std::string layoutAlgorithm; +}; + + +YGraph::YGraph( YWidget * parent, const std::string & filename, const std::string & layoutAlgorithm ) + : YWidget( parent ) + , priv( new YGraphPrivate( filename, layoutAlgorithm ) ) +{ + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YGraph::YGraph( YWidget * parent, /* graph_t */ void * graph ) + : YWidget( parent ) + , priv( new YGraphPrivate( "", "" ) ) +{ + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YGraph::~YGraph() +{ + // NOP +} + + +std::string +YGraph::filename() const +{ + return priv->filename; +} + + +void +YGraph::setFilename( const std::string & filename ) +{ + priv->filename = filename; + renderGraph( filename, layoutAlgorithm() ); +} + + +std::string +YGraph::layoutAlgorithm() const +{ + return priv->layoutAlgorithm; +} + + +void +YGraph::setGraph( /* graph_t */ void * graph ) +{ + priv->filename.clear(); + renderGraph( graph ); +} + + +void +YGraph::setLayoutAlgorithm( const std::string & layoutAlgorithm ) +{ + priv->layoutAlgorithm = layoutAlgorithm; +} + + +std::string +YGraph::activatedNode() const +{ + return ""; +} + + +const YPropertySet & +YGraph::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Filename name of the file describing the graph + * @property std::string Layout layout-algorithm used from the graph + * @property std::string Item activated node (read-only) + */ + propSet.add( YProperty( YUIProperty_Filename, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Layout, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Item, YStringProperty, true ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YGraph::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Filename ) setFilename( val.stringVal() ); + else if ( propertyName == YUIProperty_Layout ) setLayoutAlgorithm( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YGraph::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Filename ) return YPropertyValue( filename() ); + else if ( propertyName == YUIProperty_Layout ) return YPropertyValue( layoutAlgorithm() ); + else if ( propertyName == YUIProperty_Item ) return YPropertyValue( activatedNode() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YGraph.h b/src/YGraph.h new file mode 100644 index 0000000..d90d1ae --- /dev/null +++ b/src/YGraph.h @@ -0,0 +1,166 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YGraph.h + + Author: Arvin Schnell + +/-*/ + +#ifndef YGraph_h +#define YGraph_h + +#include "YWidget.h" + +/* + * Do not include graphviz/types.h here since it conflicts with ncurses + * headers. People should finally start to use C++ and namespaces! + * + * The previous workaround of inserting the graph_t definition here does not + * work with graphviz >= 2.30.0 since it depends on the define WITH_CGRAPH. + * + * For that reason a lot of functions simply take a void* instead of graph_t*. + */ + +class YGraphPrivate; + +/** + * A graph with nodes and edges, rendered with Graphviz. + **/ +class YGraph : public YWidget +{ +protected: + + /** + * Constructor. + * + * Loads a graph in DOT format from filename and uses the layout algorithm + * layoutAlgorithm to layout and then render the graph. The layout + * algorithm can be any string accepted by the function gvLayout from + * graphviz, e.g. "dot" or "neato". + **/ + YGraph( YWidget * parent, const std::string & filename, const std::string & layoutAlgorithm ); + + /** + * Constructor. + * + * Renders the graph. The graph must already contain layout information. + **/ + YGraph( YWidget * parent, /* graph_t */ void * graph ); + +public: + + /** + * Destructor. + **/ + virtual ~YGraph(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YGraph"; } + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Return the filename that describes the graph. + **/ + std::string filename() const; + + /** + * Set the filename that describes the graph and render the graph. + * Derived classes can reimplent this, but they should call this base + * class method in the new implementation. Most derived classes only need + * to implement renderGraph(). + **/ + virtual void setFilename( const std::string & filename ); + + /** + * Return the layout-algorithm used for the graph. + **/ + std::string layoutAlgorithm() const; + + /** + * Set the layout-algorithm used for the graph. Derived classes can + * reimplent this, but they should call this base class method in the new + * implementation. + **/ + virtual void setLayoutAlgorithm( const std::string & filename ); + + /** + * Render the graph. Derived classes can reimplent this, but they should + * call this base class method in the new implementation. Most derived + * classes only need to implement renderGraph(). + **/ + virtual void setGraph( /* graph_t */ void * graph ); + + /** + * Return name of activated node. Activation can happen due to e.g. single + * right mouse click (context menu) or double left mouse click. + */ + virtual std::string activatedNode() const; + +protected: + + /** + * Render the graph from the filename. Derived classes are required to + * implement this. + **/ + virtual void renderGraph( const std::string & filename, const std::string & layoutAlgorithm ) = 0; + + /** + * Render the graph. Derived classes are required to implement this. + **/ + virtual void renderGraph( /* graph_t */ void * graph ) = 0; + +private: + + ImplPtr priv; + +}; + + +#endif // YGraph_h diff --git a/src/YGraphPlugin.h b/src/YGraphPlugin.h new file mode 100644 index 0000000..1012f4b --- /dev/null +++ b/src/YGraphPlugin.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YGraphPlugin.h + + Author: Arvin Schnell + +/-*/ + +#ifndef YGraphPlugin_h +#define YGraphPlugin_h + +#include "YUIPlugin.h" + +class YWidget; +class YGraph; + + +/** + * Abstract base class for simplified access to UI plugins for graph widget. + **/ +class YGraphPlugin : public YUIPlugin +{ +protected: + /** + * Constructor: Load the specified plugin library + * from the standard UI plugin directory (/usr/lib/yui/). + **/ + YGraphPlugin( const char * pluginLibBaseName ) + : YUIPlugin( pluginLibBaseName ) {} + + /** + * Destructor. Calls dlclose() which will unload the plugin library if it + * is no longer used, i.e. if the reference count dlopen() uses reaches 0. + **/ + virtual ~YGraphPlugin() {} + +public: + /** + * Create a graph widget. + * Derived classes need to implement this. + * + * This might return 0 if the plugin lib could not be loaded or if the + * appropriate symbol could not be located in the plugin lib. + **/ + virtual YGraph * createGraph( YWidget * parent, const std::string & filename, + const std::string & layoutAlgorithm ) = 0; +}; + + +#endif // YGraphPlugin_h diff --git a/src/YIconLoader.cc b/src/YIconLoader.cc new file mode 100644 index 0000000..1040789 --- /dev/null +++ b/src/YIconLoader.cc @@ -0,0 +1,117 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YIconLoader.cc + + Author: Katarína Machálková + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include +#include + +#include "YIconLoader.h" + +using std::endl; + +#define FALLBACK_ICON_PATH "/usr/share/icons/hicolor/" + +YIconLoader::YIconLoader() +{ + addIconSearchPath(FALLBACK_ICON_PATH); +} + +YIconLoader::~YIconLoader() +{ +} + +void YIconLoader::setIconBasePath( std::string path ) +{ + _iconBasePath = path; +} + +std::string YIconLoader::iconBasePath() const +{ + return _iconBasePath; +} + +void YIconLoader::addIconSearchPath( std::string path ) +{ + icon_dirs.push_front( path ); +} + +std::string YIconLoader::findIcon( std::string name ) +{ + // No extension -> add some + std::string::size_type loc = name.find(".png"); + if ( loc == std::string::npos ) + name += ".png"; + + // Absolute path -> return it + if (name[0] == '/') + return name; + + std::string fullPath; + + // Look in global search path + if ( !_iconBasePath.empty () ) + { + fullPath = _iconBasePath + name; + if ( fileExists ( fullPath ) ) + { + yuiMilestone() << "Found " << name << " in global search path" << endl; + return fullPath; + } + } + + // Now search the fallback dirs + std::list::iterator listIt = icon_dirs.begin(); + + while( listIt != icon_dirs.end() ) + { + // Something like relative path + if ( name.find('/') != std::string::npos ) + fullPath = *listIt + name; + // No '/' chars, just the name -> use '22x22/apps' fallback + else + fullPath = *listIt + "22x22/apps/" + name; + + if ( fileExists( fullPath ) ) + { + yuiMilestone() << "Found " << name << " in " << *listIt << " search path" << endl; + return fullPath; + } + + yuiMilestone() << name << " not found in " << *listIt << " search path, skipping" << endl; + listIt++; + } + + return ""; +} + +bool YIconLoader::fileExists( std::string fname ) +{ + struct stat fileInfo; + int ret = stat (fname.c_str(), &fileInfo); + + return ( ret == 0 ); +} diff --git a/src/YIconLoader.h b/src/YIconLoader.h new file mode 100644 index 0000000..8b05f4c --- /dev/null +++ b/src/YIconLoader.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YIconLoader.cc + + Author: Katarína Machálková + +/-*/ + + +#ifndef YIconLoader_H +#define YIconLoader_H + +#include +#include + +class YIconLoader +{ +public: + + YIconLoader(); + ~YIconLoader(); + + std::string findIcon( std::string name ); + + //FIXME: these two are here for compatibility reasons + // deprecate them in due course and treat base path just + // like any other search path + void setIconBasePath( std::string path ); + std::string iconBasePath() const; + + void addIconSearchPath( std::string path ); + +private: + + std::string _iconBasePath; + std::list icon_dirs; + + bool fileExists( std::string fname ); +}; + +#endif diff --git a/src/YImage.cc b/src/YImage.cc new file mode 100644 index 0000000..648253f --- /dev/null +++ b/src/YImage.cc @@ -0,0 +1,111 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YImage.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YImage.h" +#include "YBothDim.h" + + +struct YImagePrivate +{ + /** + * Constructor. + **/ + YImagePrivate( const std::string & imageFileName, bool animated ) + : imageFileName( imageFileName ) + , animated( animated ) + , autoScale( false ) + { + zeroSize.hor = false; + zeroSize.vert = false; + } + + + std::string imageFileName; + bool animated; + YBothDim zeroSize; + bool autoScale; +}; + + + + +YImage::YImage( YWidget * parent, + const std::string & imageFileName, + bool animated ) + : YWidget( parent ) + , priv( new YImagePrivate( imageFileName, animated ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YImage::~YImage() +{ + // NOP +} + + +std::string YImage::imageFileName() const +{ + return priv->imageFileName; +} + + +bool YImage::animated() const +{ + return priv->animated; +} + + +void YImage::setImage( const std::string & imageFileName, bool animated ) +{ + priv->imageFileName = imageFileName; + priv->animated = animated; +} + + +bool YImage::hasZeroSize( YUIDimension dim ) const +{ + return priv->zeroSize[ dim ]; +} + + +void YImage::setZeroSize( YUIDimension dim, bool zeroSize ) +{ + priv->zeroSize[ dim ] = zeroSize; + setStretchable( dim, zeroSize ); +} + + +bool YImage::autoScale() const +{ + return priv->autoScale; +} + + +void YImage::setAutoScale( bool autoScale ) +{ + priv->autoScale = autoScale; +} diff --git a/src/YImage.h b/src/YImage.h new file mode 100644 index 0000000..17bea21 --- /dev/null +++ b/src/YImage.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YImage.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YImage_h +#define YImage_h + +#include "YWidget.h" +#include + + +class YImagePrivate; + +/** + * A picture, possibly animated, loaded from a file. + **/ +class YImage : public YWidget +{ +public: + /** + * Constructor. + * + * 'animated' indicates if 'imageFileName' is an animated image format + * (e.g., MNG). + **/ + YImage( YWidget * parent, + const std::string & imageFileName, + bool animated = false ); + + /** + * Destructor. + **/ + virtual ~YImage(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YImage"; } + + /** + * Return the file name of this widget's image. + **/ + std::string imageFileName() const; + + /** + * Returns 'true' if the current image is an animated image format (e.g., + * MNG). + **/ + bool animated() const; + + /** + * Set and display a new image (or movie if animated is 'true'). + * + * Derived classes should overwrite this, but call this base class function + * in the new function. + **/ + virtual void setImage( const std::string & imageFileName, bool animated = false ); + + /** + * Set and display a movie (an animated image). + **/ + void setMovie( const std::string & movieFileName ) + { setImage( movieFileName, true ); } + + /** + * Return 'true' if the image widget should be stretchable with a default + * width of 0 in the specified dimension. This is useful if the widget + * width is determined by outside constraints, like the width of a + * neighbouring widget. + **/ + bool hasZeroSize( YUIDimension dim ) const; + + /** + * Make the image widget stretchable with a default size of 0 in the + * specified dimension. This is useful if the widget width is determined by + * outside constraints, like the width of a neighbouring widget. + * + * This function is intentionally not virtual because it is only relevant + * during the next geometry update, in which case the derived class has to + * check this value anyway. + **/ + void setZeroSize( YUIDimension dim, bool zeroSize = true ); + + /** + * Return 'true' if the image should be scaled to fit into the available + * space. + **/ + bool autoScale() const; + + /** + * Make the image fit into the available space. + * + * Derived classes should overwrite this, but call this base class function + * in the new function. + **/ + virtual void setAutoScale( bool autoScale = true ); + + +private: + + ImplPtr priv; +}; + + +#endif // YImage_h diff --git a/src/YInputField.cc b/src/YInputField.cc new file mode 100644 index 0000000..d41a0f8 --- /dev/null +++ b/src/YInputField.cc @@ -0,0 +1,198 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YInputField.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YMacroRecorder.h" +#include "YInputField.h" + + + +struct YInputFieldPrivate +{ + YInputFieldPrivate( std::string label, bool passwordMode ) + : label( label ) + , passwordMode( passwordMode ) + , shrinkable( false ) + , inputMaxLength( -1 ) + {} + + std::string label; + bool passwordMode; + bool shrinkable; + std::string validChars; + int inputMaxLength; +}; + + + +YInputField::YInputField( YWidget * parent, const std::string & label, bool passwordMode ) + : YWidget( parent ) + , priv( new YInputFieldPrivate( label, passwordMode ) ) +{ + YUI_CHECK_NEW( priv ); + + // setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, false ); +} + + +YInputField::~YInputField() +{ + // NOP +} + + +std::string YInputField::label() const +{ + return priv->label; +} + + +void YInputField::setLabel( const std::string & label ) +{ + priv->label = label; +} + + +bool YInputField::passwordMode() const +{ + return priv->passwordMode; +} + + +bool YInputField::shrinkable() const +{ + return priv->shrinkable; +} + + +void YInputField::setShrinkable( bool shrinkable ) +{ + priv->shrinkable = shrinkable; + // setDefaultStretchable( YD_HORIZ, ! shrinkable ); +} + + +std::string YInputField::validChars() +{ + return priv->validChars; +} + + +void YInputField::setValidChars( const std::string & newValidChars ) +{ + priv->validChars= newValidChars; +} + + +int YInputField::inputMaxLength() const +{ + return priv->inputMaxLength; +} + + +void YInputField::setInputMaxLength( int len ) +{ + priv->inputMaxLength = len; +} + + +const YPropertySet & +YInputField::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Value the input field's contents (the user input) + * @property std::string Label caption above the input field + * @property std::string ValidChars set of valid input characters + * @property integer InputMaxLength maximum number of input characters + */ + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_ValidChars, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_InputMaxLength, YIntegerProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YInputField::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.stringVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_ValidChars ) setValidChars( val.stringVal() ); + else if ( propertyName == YUIProperty_InputMaxLength ) setInputMaxLength( val.integerVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YInputField::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_ValidChars ) return YPropertyValue( validChars() ); + else if ( propertyName == YUIProperty_InputMaxLength ) return YPropertyValue( inputMaxLength() ); + else + { + return YWidget::getProperty( propertyName ); + } +} + + +void +YInputField::saveUserInput( YMacroRecorder *macroRecorder ) +{ + if ( ! passwordMode() ) // Don't record passwords in the macro file + { + macroRecorder->recordWidgetProperty( this, YUIProperty_Value ); + } +} + + +const char * +YInputField::widgetClass() const +{ + if ( priv->passwordMode ) return "YPasswordField"; + else return "YInputField"; +} diff --git a/src/YInputField.h b/src/YInputField.h new file mode 100644 index 0000000..70641ce --- /dev/null +++ b/src/YInputField.h @@ -0,0 +1,215 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YInputField.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YInputField_h +#define YInputField_h + +#include +#include "YWidget.h" + +class YInputFieldPrivate; + + + +/** + * InputField: General purpose one line input field for entering text and other + * data. Can be used for entering passwords with a "*" echoed for every + * character typed. + * + * Like most widgets, the InputField has a label (a caption) above the input + * field itself. The label can and should get a keyboard shortcut (specified + * with '&') that will make the input field receive the keyboard focus with a + * special key combination ("&Name" -> Alt-N or Ctrl-N will make the keyboard + * focus jump to the corresponding input field). + **/ +class YInputField : public YWidget +{ +protected: + /** + * Constructor. + * + * Create an input field with 'label' as the caption. + * If 'passwordMode' is set, the input will be not be echoed as clear text. + **/ + YInputField( YWidget * parent, + const std::string & label, + bool passwordMode = false ); + +public: + /** + * Destructor. + **/ + virtual ~YInputField(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const; + + /** + * Get the current value (the text entered by the user or set from the + * outside) of this input field. + * + * Derived classes are required to implement this. + **/ + virtual std::string value() = 0; + + /** + * Set the current value (the text entered by the user or set from the + * outside) of this input field. + * + * Derived classes are required to implement this. + **/ + virtual void setValue( const std::string & text ) = 0; + + /** + * Get the label (the caption above the input field). + **/ + std::string label() const; + + /** + * Set the label (the caption above the input field). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Returns 'true' if this input field is in password mode, i.e. if there + * should be no on-screen echo or only a '*' for each character typed. + * + * Notice that this can only be set in the constructor. + **/ + bool passwordMode() const; + + /** + * Get the valid input characters. No input validation is performed (i.e., + * the user can enter anything) if this is empty. + **/ + std::string validChars(); + + /** + * Set the valid input characters. No input validation is performed (i.e., + * the user can enter anything) if this is empty. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setValidChars( const std::string & validChars ); + + /** + * The maximum input length, i.e., the maximum number of characters the + * user can enter. -1 means no limit. + **/ + int inputMaxLength() const; + + /** + * Set the maximum input length, i.e., the maximum number of characters the + * user can enter. -1 means no limit. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setInputMaxLength( int numberOfChars ); + + /** + * Return 'true' if this InputField should be very small. + **/ + bool shrinkable() const; + + /** + * Make this InputField very small. This will take effect only upon the + * next geometry management run. + * + * Derived classes can overwrite this, but should call this base class + * function in the new function. + **/ + virtual void setShrinkable( bool shrinkable = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + /** + * Save the widget's user input to a macro recorder. + * + * Reimplemented from YWidget to avoid recording passwords. + **/ + virtual void saveUserInput( YMacroRecorder *macroRecorder ); + +private: + + ImplPtr priv; +}; + + +#endif // YInputField_h diff --git a/src/YIntField.cc b/src/YIntField.cc new file mode 100644 index 0000000..04389dd --- /dev/null +++ b/src/YIntField.cc @@ -0,0 +1,193 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YIntField.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YIntField.h" + + +struct YIntFieldPrivate +{ + YIntFieldPrivate( const std::string & label, + int minValue, + int maxValue ) + : label( label ) + , minValue( minValue ) + , maxValue( maxValue ) + {} + + std::string label; + int minValue; + int maxValue; +}; + + + + +YIntField::YIntField( YWidget * parent, + const std::string & label, + int minValue, + int maxValue ) + : YWidget( parent ) + , priv( new YIntFieldPrivate( label, minValue, maxValue ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setStretchable( YD_VERT, false ); +} + + +YIntField::~YIntField() +{ + // NOP +} + + +int +YIntField::enforceRange( int val ) const +{ + if ( val < priv->minValue ) + val = priv->minValue; + + if ( val > priv->maxValue ) + val = priv->maxValue; + + return val; +} + + +int +YIntField::minValue() const +{ + return priv->minValue; +} + + +void +YIntField::setMinValue( int val ) +{ + priv->minValue = val; + + int oldValue = value(); + int newValue = enforceRange ( oldValue ); + + if ( oldValue != newValue ) + setValue( newValue ); // This might be expensive +} + + +int +YIntField::maxValue() const +{ + return priv->maxValue; +} + + +void +YIntField::setMaxValue( int val ) +{ + priv->maxValue = val; + + int oldValue = value(); + int newValue = enforceRange ( oldValue ); + + if ( oldValue != newValue ) + setValue( newValue ); // This might be expensive +} + + +std::string +YIntField::label() const +{ + return priv->label; +} + + +void +YIntField::setLabel( const std::string & label ) +{ + priv->label = label; +} + + + +const YPropertySet & +YIntField::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property integer Value the field's contents (the user input) + * @property integer MinValue the minimum value + * @property integer MaxValue the maximum value + * @property std::string Label caption above the field + */ + propSet.add( YProperty( YUIProperty_Value, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_MinValue, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_MaxValue, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YIntField::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue ( val.integerVal() ); + else if ( propertyName == YUIProperty_MinValue ) setMinValue( val.integerVal() ); + else if ( propertyName == YUIProperty_MaxValue ) setMaxValue( val.integerVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YIntField::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + if ( propertyName == YUIProperty_MinValue ) return YPropertyValue( minValue() ); + if ( propertyName == YUIProperty_MaxValue ) return YPropertyValue( maxValue() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YIntField.h b/src/YIntField.h new file mode 100644 index 0000000..9da0537 --- /dev/null +++ b/src/YIntField.h @@ -0,0 +1,195 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YIntField.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YIntField_h +#define YIntField_h + +#include "YWidget.h" + +class YIntFieldPrivate; + + + +/** + * IntField: Input field for integer values. Enforces input range between a + * specified minimum and maximum value. + **/ +class YIntField : public YWidget +{ +protected: + /** + * Constructor. + * + * Create an IntField with 'label' as the caption, and the specified minimum + * and maximum values. + * + * Note that YWidgetFactory::createIntField() also has an 'initialValue' + * parameter that is not used here (because the current value is not stored + * in this base class, but in the derived class). + **/ + YIntField( YWidget * parent, + const std::string & label, + int minValue, + int maxValue ); + +public: + /** + * Destructor. + **/ + virtual ~YIntField(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YIntField"; } + + /** + * Get the current value (the number entered by the user or set from the + * outside) of this IntField. + * + * Derived classes are required to implement this. + **/ + virtual int value() = 0; + + /** + * Set the current value (the number entered by the user or set from the + * outside) of this IntField. This method enforces 'val to be between + * minValue and maxValue. + **/ + void setValue( int val ) { setValueInternal( enforceRange( val ) ); } + +protected: + + /** + * Set the current value (the number entered by the user or set from the + * outside) of this IntField. 'val' is guaranteed to be between minValue + * and maxValue; no further checks are required. + * + * Derived classes are required to implement this method. + **/ + virtual void setValueInternal( int val ) = 0; + + /** + * Enforce 'val' to be between minValue and maxValue. + * Return a value that is in range. This does not change the internally + * stored value of this IntField in any way. + **/ + int enforceRange( int val ) const; + +public: + + /** + * Return the minimum value. + **/ + int minValue() const; + + /** + * Set a new minimum value. If the current value is less than that, it will + * be set to the new minimum. + **/ + void setMinValue( int val ); + + /** + * Return the maximum value. + **/ + int maxValue() const; + + /** + * Set a new maximum value. If the current value is greater than that, it + * will be set to the new maximum. + **/ + void setMaxValue( int val ); + + /** + * Get the label (the caption above the input field). + **/ + std::string label() const; + + /** + * Set the label (the caption above the input field). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + +private: + + ImplPtr priv; +}; + + +#endif // YIntField_h diff --git a/src/YItem.cc b/src/YItem.cc new file mode 100644 index 0000000..88a1588 --- /dev/null +++ b/src/YItem.cc @@ -0,0 +1,33 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YItem.cc + + Author: Stefan Hundhammer + +/-*/ + +#include "YItem.h" + +/** + * Static children collection that is always empty so the children + * iterators of this base class have something valid to return. + * + * No item will ever be added to this collection. + **/ +YItemCollection YItem::_noChildren; diff --git a/src/YItem.h b/src/YItem.h new file mode 100644 index 0000000..b8f825e --- /dev/null +++ b/src/YItem.h @@ -0,0 +1,209 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YItem.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YItem_h +#define YItem_h + +#include +#include + + +class YItem; + +// without "documenting" the file, typedefs will be dropped +//! @file + +//! Collection of pointers to YItem. +typedef std::vector YItemCollection; +//! Mutable iterator over @ref YItemCollection. +typedef YItemCollection::iterator YItemIterator; +//! Const iterator over @ref YItemCollection. +typedef YItemCollection::const_iterator YItemConstIterator; + + +/** + * Simple item class for SelectionBox, ComboBox, MultiSelectionBox etc. items. + * This class provides stubs for children management. + **/ +class YItem +{ +public: + /** + * Constructor with just the label and optionally the selected state. + **/ + YItem( const std::string & label, bool selected = false ) + : _label( label ) + , _selected( selected ) + , _index( -1 ) + , _data( 0 ) + {} + + /** + * Constructor with label and icon name and optionally the selected state. + **/ + YItem( const std::string & label, const std::string & iconName, bool selected = false ) + : _label( label ) + , _iconName( iconName ) + , _selected( selected ) + , _index( -1 ) + , _data( 0 ) + {} + + /** + * Destructor. + **/ + virtual ~YItem() {} + + /** + * Return this item's label. This is what the user sees in a dialog, so + * this will usually be a translated text. + **/ + std::string label() const { return _label; } + + /** + * Set this item's label. + **/ + void setLabel( const std::string & newLabel ) { _label = newLabel; } + + /** + * Return this item's icon name. + **/ + std::string iconName() const { return _iconName; } + + /** + * Return 'true' if this item has an icon name. + **/ + bool hasIconName() const { return ! _iconName.empty(); } + + /** + * Set this item's icon name. + **/ + void setIconName( const std::string & newIconName ) { _iconName = newIconName; } + + /** + * Return 'true' if this item is currently selected. + **/ + bool selected() const { return _selected; } + + /** + * Select or unselect this item. This does not have any effect on any other + * item; if it is desired that only one item is selected at any time, the + * caller has to take care of that. + **/ + void setSelected( bool sel = true ) { _selected = sel; } + + /** + * Set this item's index. + **/ + void setIndex( int index ) { _index = index; } + + /** + * Return the index of this item (as set with setIndex() ). + **/ + int index() const { return _index; } + + /** + * Set the opaque data pointer for application use. + * + * Applications can use this to store the pointer to a counterpart of this + * tree item. It is the application's responsibility to watch for dangling + * pointers and possibliy deleting the data. All this class ever does with + * this pointer is to store it. + **/ + void setData( void * newData ) { _data = newData; } + + /** + * Return the opaque data pointer. + **/ + void * data() const { return _data; } + + // + // Children management stubs. + // + // Derived classes that can handle child items should reimplement those + // functions. + // The following default implementations don't do anything with children; + // they act as if this item didn't have any children. + // + + /** + * Return 'true' if this item has any child items. + **/ + virtual bool hasChildren() const { return false; } + + /** + * Return an iterator that points to the first child item of this item. + * + * This default implementation returns the 'end' iterator of the + * class-static always empty _noChildren YItemCollection. + * It is safe to use this iterator in classic iterator loops: + * + * for ( YItemIterator it = myItem->childrenBegin(); + * it != myItem->childrenEnd(); + * ++it ) + * { + * ... + * } + * + * The loop body will only ever be executed if this item is a derived class + * that actually manages child items. + **/ + virtual YItemIterator childrenBegin() { return _noChildren.end(); } + virtual YItemConstIterator childrenBegin() const { return _noChildren.end(); } + + /** + * Return an iterator that points after the last child item of this item. + * + * This default implementation returns the 'end' iterator of the + * class-static always empty _noChildren YItemCollection. + **/ + virtual YItemIterator childrenEnd() { return _noChildren.end(); } + virtual YItemConstIterator childrenEnd() const { return _noChildren.end(); } + + /** + * Returns this item's parent item or 0 if it is a toplevel item. + * This default implementation always returns 0. + * Derived classes that handle children should reimplement this. + **/ + virtual YItem * parent() const { return 0; } + + +private: + + std::string _label; + std::string _iconName; + bool _selected; + int _index; + void * _data; + + /** + * Static children collection that is always empty so the children + * iterators of this base class have something valid to return. + **/ + static YItemCollection _noChildren; +}; + + + +#endif // YItem_h diff --git a/src/YLabel.cc b/src/YLabel.cc new file mode 100644 index 0000000..e64dec4 --- /dev/null +++ b/src/YLabel.cc @@ -0,0 +1,191 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YLabel.cc + + Author: Stefan Hundhammer + +/-*/ + +#define MAX_DEBUG_LABEL_LEN 32 + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YLabel.h" + + +struct YLabelPrivate +{ + /** + * Constructor + **/ + YLabelPrivate( const std::string & text, + bool isHeading, + bool isOutputField ) + : text( text ) + , isHeading( isHeading ) + , isOutputField( isOutputField ) + , useBoldFont( false ) + {} + + std::string text; + bool isHeading; + bool isOutputField; + bool useBoldFont; +}; + + +YLabel::YLabel( YWidget * parent, + const std::string & text, + bool isHeading, + bool isOutputField ) + : YWidget( parent ) + , priv( new YLabelPrivate( text, isHeading, isOutputField ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YLabel::~YLabel() +{ + // NOP +} + + +std::string YLabel::text() const +{ + return priv->text; +} + + +void YLabel::setText( const std::string & newText ) +{ + priv->text = newText; +} + + +bool YLabel::isHeading() const +{ + return priv->isHeading; +} + + +bool YLabel::isOutputField() const +{ + return priv->isOutputField; +} + + +bool YLabel::useBoldFont() const +{ + return priv->useBoldFont; +} + + +void YLabel::setUseBoldFont( bool bold ) +{ + priv->useBoldFont = bold; +} + + +const YPropertySet & +YLabel::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Label the label text + * @property std::string Value the label text (alias for Label) + * @property std::string Text the label text (alias for Label) + */ + + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Text, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YLabel::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Label ) setText( val.stringVal() ); + else if ( propertyName == YUIProperty_Value ) setText( val.stringVal() ); + else if ( propertyName == YUIProperty_Text ) setText( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YLabel::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Label ) return YPropertyValue( text() ); + else if ( propertyName == YUIProperty_Value ) return YPropertyValue( text() ); + else if ( propertyName == YUIProperty_Text ) return YPropertyValue( text() ); + else + { + return YWidget::getProperty( propertyName ); + } +} + + +std::string YLabel::debugLabel() const +{ + std::string label = text(); + + if ( label.size() > MAX_DEBUG_LABEL_LEN ) + { + label.resize( MAX_DEBUG_LABEL_LEN ); + label.append( "..." ); + } + + for ( std::string::size_type i=0; i < label.size(); i++ ) + { + if ( label[i] == '\n' ) label[i] = ' '; + if ( label[i] == '\"' ) label[i] = ' '; + } + + return label; +} + + + +const char * +YLabel::widgetClass() const +{ + if ( priv->isHeading ) return "YLabel_Heading"; + else if ( priv->isOutputField ) return "YLabel_OutputField"; + else return "YLabel"; +} diff --git a/src/YLabel.h b/src/YLabel.h new file mode 100644 index 0000000..d2fff61 --- /dev/null +++ b/src/YLabel.h @@ -0,0 +1,176 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YLabel.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YLabel_h +#define YLabel_h + +#include "YWidget.h" +#include +#include "ImplPtr.h" + + +class YLabelPrivate; + +/** + * Implementation of the Label, Heading and OutputField widgets + **/ +class YLabel : public YWidget +{ +public: + + /** + * Constructor. + * + * 'isHeading' indicates if this should be displayed as a Heading widget, + * i.e. with a bold and/or larger font. + * This cannot be changed after creating the widget. + * + * 'isOutputField' indicates if this should be displayed as an OutputField + * widget, i.e. similar to an InputField the user can't change. + * This cannot be changed after creating the widget. + **/ + YLabel( YWidget * parent, + const std::string & text, + bool isHeading = false, + bool isOutputField = false ); + + /** + * Destructor. + **/ + virtual ~YLabel(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + * + * Reimplemented from YWidget. + **/ + virtual const char * widgetClass() const; + + /** + * Return the text the widget displays. + **/ + std::string text() const; + + /** + * Aliases for text(). + **/ + std::string value() const { return text(); } + std::string label() const { return text(); } + + /** + * Set the text the widget displays. + * + * Derived classes should overwrite this, but call this base class function + * in the overwritten function. + **/ + virtual void setText( const std::string & newText ); + + /** + * Aliases for setText(). + **/ + void setValue( const std::string & newValue ) { setText( newValue ); } + void setLabel( const std::string & newLabel ) { setText( newLabel ); } + + /** + * Return 'true' if this is a Heading widget, i.e., it should display its + * text in a bold and/or larger font. + * + * This cannot be changed after creating the widget. + **/ + bool isHeading() const; + + /** + * Return 'true' if this is an OutputField widget, i.e., it should display + * its text similar to an InputField the user can't change. + * + * This cannot be changed after creating the widget. + **/ + bool isOutputField() const; + + /** + * Return 'true' if a bold font should be used. + **/ + bool useBoldFont() const; + + /** + * Switch bold font on or off. + * + * Derived classes should overwrite this, but call this base class function + * in the overwritten function. + **/ + virtual void setUseBoldFont( bool bold = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property set upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Returns a descriptive label of this widget instance for debugging. + * + * Reimplemented from YWidget since a YLabel doesn't have a shortcut + * property. + **/ + virtual std::string debugLabel() const; + +private: + + ImplPtr priv; +}; + + +typedef YLabel YHeading; +typedef YLabel YOutputField; + + +#endif // YLabel_h diff --git a/src/YLayoutBox.cc b/src/YLayoutBox.cc new file mode 100644 index 0000000..0b042b6 --- /dev/null +++ b/src/YLayoutBox.cc @@ -0,0 +1,778 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YLayoutBox.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include // std::setw() +#include // std::max() + +#define YUILogComponent "ui-layout" +#include "YUILog.h" + +#include "YLayoutBox.h" +#include "YAlignment.h" +#include "YSpacing.h" +#include "YUI.h" +#include "YApplication.h" + +using std::endl; +using std::setw; +using std::max; +using std::boolalpha; + +struct YLayoutBoxPrivate +{ + /** + * Constructor + **/ + YLayoutBoxPrivate( YUIDimension prim ) + : primary( prim ) + , secondary( prim == YD_HORIZ ? YD_VERT : YD_HORIZ ) + , debugLayout( false ) + {} + + // + // Data members + // + + YUIDimension primary; + YUIDimension secondary; + bool debugLayout; +}; + + + + +YLayoutBox::YLayoutBox( YWidget * parent, YUIDimension primaryDimension ) + : YWidget( parent ) + , priv( new YLayoutBoxPrivate( primaryDimension ) ) +{ + YUI_CHECK_NEW( priv ); + setChildrenManager( new YWidgetChildrenManager( this ) ); +} + + +YLayoutBox::~YLayoutBox() +{ + // NOP +} + + +YUIDimension +YLayoutBox::primary() const +{ + return priv->primary; +} + + +YUIDimension +YLayoutBox::secondary() const +{ + return priv->secondary; +} + + +bool +YLayoutBox::debugLayout() const +{ + return priv->debugLayout; +} + +void +YLayoutBox::setDebugLayout( bool deb ) +{ + priv->debugLayout = deb; + + yuiDebug() << "YLayoutBox: Layout debugging: " << boolalpha << deb << endl; +} + + +int +YLayoutBox::preferredSize( YUIDimension dimension ) +{ + if ( dimension == secondary() ) // the easy case first: secondary dimension + { + return childrenMaxPreferredSize( dimension ); + } + else + { + /* + * In the primary dimension things are much more complicated: We want to + * honor any weights specified under all circumstances. So we first + * need to determine the "dominating child" - the widget that determines the + * overall size with respect to its weight in that dimension. Once we + * know that, we need to stretch all other weighted children accordingly + * so the weight ratios are respected. + * + * As a final step, the preferred sizes of all children that don't have + * a weight attached are summed up. + */ + + int size = 0L; + + // Search for the dominating child + YWidget * dominatingChild = findDominatingChild(); + + if ( dominatingChild ) + { + // Calculate size of all weighted widgets. + + size = dominatingChild->preferredSize( primary() ) + * childrenTotalWeight( primary() ) + / dominatingChild->weight( primary() ); + + // Maintain this order of calculation in order to minimize integer + // rounding errors! + } + + + // Add up the size of all non-weighted children; + // they will get their respective preferred size. + + size += totalNonWeightedChildrenPreferredSize( primary() ); + + return size; + } +} + + +int YLayoutBox::preferredWidth() +{ + return preferredSize( YD_HORIZ ); +} + + +int YLayoutBox::preferredHeight() +{ + return preferredSize( YD_VERT ); +} + + +/* + * Search for the "dominating child" widget. + * + * This is the widget that determines the overall size of the + * container with respect to all children's weights: It is the child + * with the maximum ratio of preferred size and weight. All other + * weighted children need to be stretched accordingly so the weight + * ratios can be maintained. + * + * Returns 0 if there is no dominating child, i.e. if there are only + * non-weighted children. + */ + +YWidget * +YLayoutBox::findDominatingChild() +{ + YWidget * dominatingChild = 0; + double dominatingRatio = 0.0; + double ratio; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YWidget * child = *it; + + if ( child->weight( primary() ) != 0 ) // avoid division by zero + { + ratio = ( ( double ) child->preferredSize( primary() ) ) + / child->weight( primary() ); + + if ( ratio > dominatingRatio ) // we have a new dominating child + { + dominatingChild = child; + dominatingRatio = ratio; + } + } + } + + + if ( debugLayout() ) + { + if ( dominatingChild ) + { + yuiDebug() << "Found dominating child: " << dominatingChild + << " - preferred size: " << dominatingChild->preferredSize( primary() ) + << ", weight: " << dominatingChild->weight( primary() ) + << endl; + } + else + { + yuiDebug() << "This layout doesn't have a dominating child." << endl; + } + } + + return dominatingChild; +} + + +int +YLayoutBox::childrenMaxPreferredSize( YUIDimension dimension ) +{ + int maxPreferredSize = 0L; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + maxPreferredSize = std::max( (*it)->preferredSize( dimension ), maxPreferredSize ); + } + + return maxPreferredSize; +} + + +int +YLayoutBox::childrenTotalWeight( YUIDimension dimension ) +{ + int totalWeight = 0L; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + totalWeight += (*it)->weight( dimension ); + } + + return totalWeight; +} + + +int +YLayoutBox::totalNonWeightedChildrenPreferredSize( YUIDimension dimension ) +{ + int size = 0L; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + if ( ! (*it)->hasWeight( dimension ) ) // non-weighted children only + size += (*it)->preferredSize( dimension ); + } + + return size; +} + + +int +YLayoutBox::countNonWeightedChildren( YUIDimension dimension ) +{ + int count = 0; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + if ( ! (*it)->hasWeight( dimension ) ) + count++; + } + + return count; +} + + +int +YLayoutBox::countStretchableChildren( YUIDimension dimension ) +{ + int count = 0; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + if ( ! (*it)->hasWeight( dimension ) && + (*it)->stretchable( dimension ) ) + count++; + } + + return count; +} + + +int +YLayoutBox::countLayoutStretchChildren( YUIDimension dimension ) +{ + int count = 0; + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + if ( ! (*it)->hasWeight( dimension ) && + isLayoutStretch( *it, dimension ) ) + count++; + } + + return count; +} + + +bool +YLayoutBox::isLayoutStretch( YWidget * child, YUIDimension dimension ) +{ + if ( ! child ) + return false; + + YSpacing * spacing = dynamic_cast (child); + + if ( spacing && spacing->stretchable( dimension ) ) + return true; + else + return false; +} + + + +bool +YLayoutBox::stretchable( YUIDimension dimension ) const +{ + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + if ( (*it)->stretchable( dimension ) || + (*it)->hasWeight( dimension ) ) + return true; + } + + return false; +} + + +void +YLayoutBox::setSize( int newWidth, int newHeight ) +{ + int count = childrenCount(); + sizeVector widths ( count ); + sizeVector heights ( count ); + posVector x_pos ( count ); + posVector y_pos ( count ); + + if ( primary() == YD_HORIZ ) + { + calcPrimaryGeometry ( newWidth, widths, x_pos ); + calcSecondaryGeometry( newHeight, heights, y_pos ); + } + else + { + calcPrimaryGeometry ( newHeight, heights, y_pos ); + calcSecondaryGeometry( newWidth, widths, x_pos ); + } + + if ( YUI::app()->reverseLayout() ) + { + // Mirror the widget X geometry for languages with left-to-right + // writing direction (Arabic, Hebrew). + + for ( int i = 0; i < childrenCount(); i++ ) + x_pos[i] = newWidth - x_pos[i] - widths[i]; + } + + doResize( widths, heights, x_pos, y_pos ); +} + + +void +YLayoutBox::calcPrimaryGeometry( int newSize, + sizeVector & childSize, + posVector & childPos ) +{ + int pos = 0L; + int distributableSize = newSize - totalNonWeightedChildrenPreferredSize( primary() ); + + if ( distributableSize >= 0L ) + { + // The (hopefully) normal case: There is enough space. + // The non-weighted children will get their preferred sizes, + // the rest will be distributed among the weighted children + // according to their respective weight ratios. + + int nonWeightedExtra = 0L; + int totalWeight = childrenTotalWeight( primary() ); + int rubberBands = 0; + int rubberBandExtra = 0L; + + if ( totalWeight <= 0 ) + { + // If there are no weighted children, equally divide the + // extra space among the stretchable children (if any). + // This includes any layout stretch spaces. + + int stretchableChildren = countStretchableChildren( primary() ); + + if ( stretchableChildren > 0 ) // avoid division by zero + nonWeightedExtra = distributableSize / stretchableChildren; + } + else + { + // If there are weighted children and there are rubber band + // widgets, equally divide any surplus space (i.e. space that + // exceeds the weighted children's preferred sizes with respect to + // their weights) between the rubber bands. + // + // This offers an easy way to make nicely even spaced buttons + // of equal size: Give all buttons a weight of 1 and insert a + // stretch (without weight!) between each. + + int surplusSize = newSize - preferredSize( primary() ); + + if ( surplusSize > 0L ) + { + rubberBands = countLayoutStretchChildren( primary() ); + + if ( rubberBands > 0 ) + { + rubberBandExtra = surplusSize / rubberBands; + distributableSize -= rubberBandExtra * rubberBands; + } + } + } + + if ( debugLayout() ) + { + yuiDebug() << "Distributing extra space" << endl; + yuiDebug() << "\tnew size: " << newSize << endl; + yuiDebug() << "\tdistributable size: " << distributableSize << endl; + yuiDebug() << "\trubber band extra: " << rubberBandExtra << endl; + yuiDebug() << "\trubber bands: " << rubberBands << endl; + yuiDebug() << "\ttotal weight: " << totalWeight << endl; + yuiDebug() << "\tnon weighted extra: " << nonWeightedExtra << endl; + } + + int i=0; + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it, i++ ) + { + YWidget * child = *it; + + if ( child->hasWeight( primary() ) ) + { + // Weighted children will get their share. + + childSize[i] = distributableSize * child->weight( primary() ) / totalWeight; + + if ( childSize[i] < child->preferredSize( primary() ) ) + { + yuiDebug() << "Layout running out of space: " + << "Resizing child widget #" << i << " ("<< child + << ") below its preferred size of " << child->preferredSize( primary() ) + << " to " << childSize[i] + << endl; + } + } + else + { + // Non-weighted children will get their preferred size. + + childSize[i] = child->preferredSize( primary() ); + + + if ( child->stretchable( primary() ) ) + { + // If there are only non-weighted children (and only then), + // the stretchable children will get their fair share of the + // extra space. + + childSize[i] += nonWeightedExtra; + } + + if ( isLayoutStretch( child, primary() ) ) + { + // If there is more than the total preferred size and there + // are rubber bands, distribute surplus space among the + // rubber bands. + + childSize[i] += rubberBandExtra; + } + } + + childPos[i] = pos; + pos += childSize[i]; + } + } + else // The pathological case: Not enough space. + { + /* + * We're in deep shit. + * + * Not only is there nothing to distribute among the weighted children, + * we also need to resize the non-weighted children below their preferred + * sizes. Let's at least treat them equally bad - divide the lost space + * among them as fair as possible. + */ + + int tooSmall = -distributableSize; + int loserCount = 0; + int totalMargins = 0L; + int remainingMargins = 0L; + double marginScale = 0.0; + + yuiDebug() << "Not enough space: " << tooSmall << " too small - check the layout!" << endl; + + + // Maybe some of the children are YAlignments with margins that can be reduced + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + if ( ! (*it)->hasWeight( primary() ) ) // children with weights will get nothing anyway + { + YAlignment * alignment = dynamic_cast (*it); + + if ( alignment ) + { + totalMargins += alignment->totalMargins( primary() ); + yuiDebug() << "Found alignment with margins" << endl; + } + } + } + + + if ( totalMargins > tooSmall ) // We can make up for insufficient space just by reducing margins + { + remainingMargins = totalMargins - tooSmall; + tooSmall = 0L; + marginScale = ( (double) remainingMargins ) / totalMargins; + + yuiDebug() << "Making up for insufficient space by reducing margins to " + << 100.0 * marginScale << "% - " + << remainingMargins << " left for margins" + << endl; + } + else // Reducing all margins to zero still doesn't solve the problem + { + tooSmall -= totalMargins; + + yuiDebug() << "Reducing all margins to 0, but still " << tooSmall << " too small" << endl; + } + + + // Calculate initial sizes + + int i=0; + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it, i++ ) + { + if ( ! (*it)->hasWeight( primary() ) ) + { + loserCount++; + childSize[i] = (*it)->preferredSize( primary() ); + + YAlignment * alignment = dynamic_cast (*it); + + if ( alignment ) // Alignment widgets may have margins we can reduce + { + int margins = alignment->totalMargins( primary() ); + childSize[i] -= margins; // Strip off original margin + + if ( remainingMargins > 0 ) // Anything left to redistribute? + { + margins = (int) marginScale * margins; // Scale down margin + childSize[i] += margins; // Add the scaled-down margin + remainingMargins -= margins; // Deduct from redistributable margin + } + } + } + else + { + // Weighted children will get nothing anyway if there is nothing + // to distribute. + + childSize[i] = 0L; + } + } + + + // Distribute loss + + int oldTooSmall = tooSmall; + int oldLoserCount = loserCount; + while ( tooSmall > 0 && loserCount > 0 ) + { + if ( debugLayout() ) + { + yuiWarning() << "Distributing insufficient space of " << tooSmall + << " among " << loserCount << " losers" + << endl; + } + + int dividedLoss = std::max( tooSmall / loserCount, 1 ); + + int i=0; + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd() && tooSmall > 0; + ++it, i++ ) + { + if ( childSize[i] < dividedLoss ) + { + // This widget is too small to take its share of the + // loss. We'll have to re-distribute the rest of the + // loss among the others. Arrgh. + + if ( childSize[i] > 0L ) + { + tooSmall -= childSize[i]; + childSize[i] = 0L; + loserCount--; + + if ( loserCount > 0 ) + dividedLoss = std::max( tooSmall / loserCount, 1 ); + } + } + else + { + childSize[i] -= dividedLoss; + tooSmall -= dividedLoss; + } + + if ( debugLayout() ) + { + YWidget * child = *it; + + yuiWarning() << "child #" << i <<" ( " << child + << " ) will get " << childSize[i] + << " - " << child->preferredSize( primary() ) - childSize[i] << " too small" + << " (preferred size: "<< child->preferredSize( primary() ) + << ", weight: " << child->weight( primary() ) + << ", stretchable: " << boolalpha << child->stretchable( primary() ) + << "), pos: " << childPos[i] + << endl; + } + } + + if ( oldTooSmall == tooSmall && + oldLoserCount == loserCount ) + { + yuiWarning() << "Preventing endless loop while layout space distribution. Break." << endl; + break; + } + + oldTooSmall = tooSmall; + oldLoserCount = loserCount; + } + + + // Calculate postitions + + for ( int i = 0, pos=0; i < childrenCount(); i++ ) + { + childPos[i] = pos; + pos += childSize[i]; + + } + + } +} + + +void +YLayoutBox::calcSecondaryGeometry( int newSize, + sizeVector & childSize, + posVector & childPos ) +{ + int i=0; + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it, i++ ) + { + YWidget * child = *it; + int preferred = child->preferredSize( secondary() ); + + if ( child->stretchable( secondary() ) || newSize < preferred || preferred == 0 ) + // Also checking for preferred == 0 to make HSpacing / VSpacing visible in YDialogSpy: + // Otherwise they would be 0 pixels wide or high, i.e. invisible + { + childSize[i] = newSize; + childPos [i] = 0L; + } + else // child is not stretchable and there is more space than it wants + { + childSize[i] = preferred; + childPos [i] = ( newSize - preferred ) / 2; // center + } + + if ( childSize[i] < preferred ) + { + yuiDebug() << "Layout running out of space: " + << "Resizing child widget #" << i + << " (" << child + << ") below its preferred size of " << preferred + << " to " << childSize[i] + << endl; + } + + if ( debugLayout() ) + { + ( childSize[i] < preferred ? yuiWarning() : yuiDebug() ) + << "child #" << i + << " (" << child + << ") will get " << childSize[i] + << " (preferred size: " << preferred + << ", weight: " << child->weight( secondary() ) + << ", stretchable: " << boolalpha << child->stretchable( secondary() ) + << "), pos: " << childPos[i] + << endl; + } + } +} + + +void +YLayoutBox::doResize( sizeVector & width, + sizeVector & height, + posVector & x_pos, + posVector & y_pos ) +{ + int i=0; + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it, i++ ) + { + YWidget * child = *it; + + child->setSize( width[i], height[i] ); + moveChild( child, x_pos[i], y_pos[i] ); + + if ( debugLayout() ) + { + yuiMilestone() << " x: " << setw( 3 ) << x_pos[i] + << " y: " << setw( 3 ) << y_pos[i] + << " w: " << setw( 3 ) << width[i] + << " h: " << setw( 3 ) << height[i] + << " " << child + << endl; + } + } +} + + +const char * +YLayoutBox::widgetClass() const +{ + return primary() == YD_VERT ? "YVBox" : "YHBox"; +} diff --git a/src/YLayoutBox.h b/src/YLayoutBox.h new file mode 100644 index 0000000..e652a45 --- /dev/null +++ b/src/YLayoutBox.h @@ -0,0 +1,224 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YLayoutBox.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YLayoutBox_h +#define YLayoutBox_h + +#include +#include "YWidget.h" + + +class YLayoutBoxPrivate; + +/** + * A vertical or horizontal stacking of widgets, implementing HBox and VBox. + **/ +class YLayoutBox : public YWidget +{ +public: + typedef std::vector sizeVector; + typedef std::vector posVector; + +protected: + /** + * Constructor. + * + * Creates a VBox for dim == YD_VERT or a HBox for YD_HORIZ. + **/ + YLayoutBox( YWidget * parent, YUIDimension dim ); + +public: + /** + * Destructor. + **/ + virtual ~YLayoutBox(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const; + + /** + * Return the primary dimension, i.e., the dimension this LayoutBox lays + * out its children in: YD_VERT for a VBox, YD_HORIZ for a HBox. + **/ + YUIDimension primary() const; + + /** + * Return the secondary dimension. + **/ + YUIDimension secondary() const; + + /** + * Returns 'true' if layout debugging (verbose logging during layout) is on. + **/ + bool debugLayout() const; + + /** + * Enable or disable layout debugging. + **/ + void setDebugLayout( bool deb = true ); + + /** + * Preferred size of the widget in the specified dimension. + * + * Reimplemented from YWidget. + **/ + virtual int preferredSize( YUIDimension dim ); + + /** + * Preferred width of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredWidth(); + + /** + * Preferred height of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredHeight(); + + /** + * Sets the size of the layout box. This is where the layout policy + * is implemented. + * + * Derived classes can reimplement this, but this base class method should + * be called in the reimplemented function. + * + * Reimplemented from YWidget. + **/ + virtual void setSize( int newWidth, int newHeight ); + + /** + * Returns the stretchability of the layout box: + * The layout box is stretchable if one of the children is stretchable in + * this dimension or if one of the child widgets has a layout weight in + * this dimension. + * + * Reimplemented from YWidget. + **/ + virtual bool stretchable( YUIDimension dimension ) const; + + /** + * Move a child to a new position. + * + * Derived classes are required to implement this. + **/ + virtual void moveChild( YWidget * child, int newX, int newY ) = 0; + + /** + * Check if this is a layout stretch widget in the specfied dimension, + * i.e. an empty widget that is stretchable. + **/ + static bool isLayoutStretch( YWidget * child, YUIDimension dimension ); + +protected: + + /** + * Add up all the children's weights. + **/ + int childrenTotalWeight( YUIDimension dimension ); + + /** + * Return the maximum preferred size of all children in the specified + * dimension. + **/ + int childrenMaxPreferredSize( YUIDimension dimension ); + + /** + * Add up all the non-weighted children's preferred sizes in the specified + * dimension. + **/ + int totalNonWeightedChildrenPreferredSize( YUIDimension dimension ); + + /** + * Count the number of non-weighted children. + **/ + int countNonWeightedChildren( YUIDimension dimension ); + + /** + * Count the number of stretchable ( non-weighted ) children. + * Note: Weighted children are _always_ considered stretchable. + **/ + int countStretchableChildren( YUIDimension dimension ); + + /** + * Count the number of "rubber bands", i.e. the number of + * stretchable layout spacings ( e.g. {H|V}Weight, + * {H|V}Spacing ). Only those without a weight are counted. + **/ + int countLayoutStretchChildren( YUIDimension dimension ); + + /** + * Determine the number of the "dominating child" - the child widget that + * determines the overall size with respect to its weight. + * + * Return 0 if there is no dominating child, i.e. none of the children has + * a weight specified. + **/ + YWidget * findDominatingChild(); + + /** + * Calculate the sizes and positions of all children in the primary + * dimension and store them in "childSize" and "childPos". + **/ + void calcPrimaryGeometry ( int newSize, + sizeVector & childSize, + posVector & childPos ); + + /** + * Calculate the sizes and positions of all children in the secondary + * dimension and store them in "childSize" and "childPos". + **/ + void calcSecondaryGeometry ( int newSize, + sizeVector & childSize, + posVector & childPos ); + + /** + * Actually perform resizing and moving the child widgets to the + * appropriate position. + * + * The vectors passed are the sizes previously calculated by + * calcPrimaryGeometry() and calcSecondaryGeometry(). + **/ + void doResize( sizeVector & width, + sizeVector & height, + posVector & x_pos, + posVector & y_pos ); + + +private: + + ImplPtr priv; +}; + + +typedef YLayoutBox YVBox; +typedef YLayoutBox YHBox; + + +#endif // YLayoutBox_h diff --git a/src/YLogView.cc b/src/YLogView.cc new file mode 100644 index 0000000..f0b14fb --- /dev/null +++ b/src/YLogView.cc @@ -0,0 +1,298 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YLogView.cc + + Author: Stefan Hundhammer + +/-*/ + +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YLogView.h" + + +typedef std::deque StringDeque; +typedef std::deque::iterator StringDequeIterator; +typedef std::deque::const_iterator StringDequeConstIterator; + + + +struct YLogViewPrivate +{ + YLogViewPrivate( const std::string & label, int visibleLines, int maxLines ) + : label( label ) + , visibleLines( visibleLines ) + , maxLines( maxLines ) + {} + + std::string label; + int visibleLines; + int maxLines; + + StringDeque logText; +}; + + + + +YLogView::YLogView( YWidget * parent, const std::string & label, int visibleLines, int maxLines ) + : YWidget( parent ) + , priv( new YLogViewPrivate( label, visibleLines, maxLines ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YLogView::~YLogView() +{ + // NOP +} + + +std::string +YLogView::label() const +{ + return priv->label; +} + + +void +YLogView::setLabel( const std::string & label ) +{ + priv->label = label; +} + + +int +YLogView::visibleLines() const +{ + return priv->visibleLines; +} + + +void +YLogView::setVisibleLines( int newVisibleLines ) +{ + priv->visibleLines = newVisibleLines; +} + + +int +YLogView::maxLines() const +{ + return priv->maxLines; +} + + +void +YLogView::setMaxLines( int newMaxLines ) +{ + int linesToDelete = priv->maxLines - newMaxLines; + priv->maxLines = newMaxLines; + + for ( int i=0; i < linesToDelete; i++ ) + priv->logText.pop_front(); + + if ( linesToDelete > 0 ) + updateDisplay(); +} + + +std::string +YLogView::logText() const +{ + std::string text; + + for ( StringDequeConstIterator it = priv->logText.begin(); + it != priv->logText.end(); + ++it ) + { + text += *it; + } + + if ( ! text.empty() ) + { + // Cut off last newline + + if ( *(text.rbegin()) == '\n' ) // Last char is a newline? + { + text.resize( text.size() - 1 ); // make one char shorter + } + } + + return text; +} + + +std::string +YLogView::lastLine() const +{ + if ( priv->logText.empty() ) + return ""; + else + return priv->logText.back(); +} + + +void +YLogView::appendLines( const std::string & newText ) +{ + std::string text = newText; + std::string::size_type from = 0; + std::string::size_type to = 0; + + + // Split the text into single lines + + while ( to < text.size() ) + { + from = to; + to = text.find( '\n', from ); + if ( to == std::string::npos ) // no more newline + to = text.size(); + else + to++; // include the newline + + // Output one single line + appendLine( text.substr( from, to - from ) ); + } + + if ( to < text.size() ) // anything left over? + { + // Output the rest + appendLine( text.substr( to, text.size() - to ) ); + } + + updateDisplay(); +} + + +void +YLogView::appendLine( const std::string & line ) +{ + priv->logText.push_back( line ); + + if ( maxLines() > 0 && priv->logText.size() > (unsigned) maxLines() ) + { + priv->logText.pop_front(); + } +} + +void +YLogView::setLogText(const std::string & text) +{ + // optimize for regular updating widget when no new content appear + if (text == logText()) + return; + + // do not use clearText as it do render and cause segfault in qt (bnc#989155) + priv->logText.clear(); + appendLines(text); +} + + +void +YLogView::clearText() +{ + priv->logText.clear(); + updateDisplay(); +} + + +int YLogView::lines() const +{ + return priv->logText.size(); +} + + +void +YLogView::updateDisplay() +{ + displayLogText( logText() ); +} + + + +const YPropertySet & +YLogView::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Value All log lines. + * @property std::string LastLine The last log line(s). Use this to append lines. + * @property integer VisibleLines Number of lines to display. Call RecalcLayout() afterwards. + * @property integer MaxLines Number of lines to store (0 for all). + * @property std::string Label Caption above the log text + */ + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_LastLine, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_VisibleLines, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_MaxLines, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YLogView::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setLogText ( val.stringVal() ); + else if ( propertyName == YUIProperty_LastLine ) appendLines ( val.stringVal() ); + else if ( propertyName == YUIProperty_VisibleLines ) setVisibleLines ( val.integerVal() ); + else if ( propertyName == YUIProperty_MaxLines ) setMaxLines ( val.integerVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel ( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YLogView::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( logText() ); + if ( propertyName == YUIProperty_LastLine ) return YPropertyValue( lastLine() ); + if ( propertyName == YUIProperty_VisibleLines ) return YPropertyValue( visibleLines() ); + if ( propertyName == YUIProperty_MaxLines ) return YPropertyValue( maxLines() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YLogView.h b/src/YLogView.h new file mode 100644 index 0000000..53fb9ee --- /dev/null +++ b/src/YLogView.h @@ -0,0 +1,222 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YLogView.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YLogView_h +#define YLogView_h + +#include "YWidget.h" + +class YLogViewPrivate; + + +/** + * LogView: A scrollable (output-only) text to display a growing log, + * very much like the "tail -f" shell command. + **/ +class YLogView : public YWidget +{ +protected: + /** + * Constructor. + * + * 'label' is the caption above the log. 'visibleLines' indicates how many + * lines should be visible by default (unless changed by other layout + * constraints), 'maxLines' specifies how many lines (always the last ones) + * to keep in the log. 0 for 'maxLines' means "keep all lines". + **/ + YLogView( YWidget * parent, + const std::string & label, + int visibleLines, + int maxLines ); + +public: + + /** + * Destructor. + **/ + virtual ~YLogView(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YLogView"; } + + /** + * Return the label (the caption above the log text). + **/ + std::string label() const; + + /** + * Set the label (the caption above the log text). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Return the number of visible lines. + **/ + int visibleLines() const; + + /** + * Set the number of visible lines. Changing this has only effect upon the + * next geometry call, so applications calling this function might want to + * trigger a re-layout afterwards. + * + * This method is intentionally not virtual: visibleLines() should be + * queried in the preferredHeight() implementation. + **/ + void setVisibleLines( int newVisibleLines ); + + /** + * Return the maximum number of lines to store. The last maxLines() lines + * of the log text will be kept. + **/ + int maxLines() const; + + /** + * Set the maximum number of lines to store. "0" means "keep all lines" + * (beware of memory overflow!). + * + * If the new value is lower than the old value, any (now) excess lines + * before the last 'newMaxLines' lines of the log text is cut off and a + * display update is triggered. + * + * This method is intentionally not virtual since a display update is + * triggered when appropriate. + **/ + void setMaxLines( int newMaxLines ); + + /** + * Return the entire log text as one large string of concatenated lines + * delimited with newlines. + **/ + std::string logText() const; + + /** + * Set (replace) the entire log text and trigger a display update. + **/ + void setLogText( const std::string & text ); + + /** + * Return the last log line. + **/ + std::string lastLine() const; + + /** + * Append one or more lines to the log text and trigger a display update. + **/ + void appendLines( const std::string & text ); + + /** + * Clear the log text and trigger a display update. + **/ + void clearText(); + + /** + * Return the current number of lines. + **/ + int lines() const; + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + +protected: + + /** + * Display the part of the log text that should be displayed. + * 'text' contains the last 'visibleLines()' lines. + * This is called whenever the log text changes. Note that the text might + * also be empty, in which case the displayed log text should be cleared. + * + * Derived classes are required to implement this. + **/ + virtual void displayLogText( const std::string & text ) = 0; + + +private: + + /** + * Append one single line to the log text. + **/ + void appendLine( const std::string & line ); + + /** + * Trigger a re-display of the log text. + **/ + void updateDisplay(); + + + // Data members + + ImplPtr priv; + +}; + + +#endif // YLogView_h diff --git a/src/YMacro.cc b/src/YMacro.cc new file mode 100644 index 0000000..d16acc3 --- /dev/null +++ b/src/YMacro.cc @@ -0,0 +1,109 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMacro.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YMacro.h" +#include "YMacroRecorder.h" +#include "YMacroPlayer.h" + + +YMacroRecorder * YMacro::_recorder = 0; +YMacroPlayer * YMacro::_player = 0; + +void YMacro::setRecorder( YMacroRecorder * recorder ) +{ + if ( _recorder ) + delete _recorder; + + _recorder = recorder; +} + + +void YMacro::setPlayer( YMacroPlayer * player ) +{ + if ( _player ) + delete _player; + + _player = player; +} + + +void YMacro::record( const std::string & macroFile ) +{ + if ( _recorder ) + _recorder->record( macroFile ); +} + + +void YMacro::endRecording() +{ + if ( _recorder ) + _recorder->endRecording(); +} + + +bool YMacro::recording() +{ + if ( _recorder ) + return _recorder->recording(); + else + return false; +} + + +void YMacro::play( const std::string & macroFile ) +{ + if ( _player ) + _player->play( macroFile ); +} + + +void YMacro::playNextBlock() +{ + if ( _player && _player->playing() ) + _player->playNextBlock(); +} + + +bool YMacro::playing() +{ + if ( _player ) + return _player->playing(); + else + return false; +} + + +void YMacro::deleteRecorder() +{ + if ( _recorder ) + delete _recorder; +} + + +void YMacro::deletePlayer() +{ + if ( _player ) + delete _player; +} diff --git a/src/YMacro.h b/src/YMacro.h new file mode 100644 index 0000000..7efd1c8 --- /dev/null +++ b/src/YMacro.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMacro.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMacro_h +#define YMacro_h + +#include + +class YMacroRecorder; +class YMacroPlayer; + + +/** + * Simple access to macro recording and playing. + * + * This class stores an instance of a macro recorder and a macro player. + * Since both YMacroRecorder and YMacroPlayer are abstract base classes, + * derived classes from either of them have to be instantiated and set + * (setRecorder(), setPlayer()) from the outside for anything to happen. Until + * that point, none of the macro operations here do anything (but also don't + * throw any error or exception). + **/ +class YMacro +{ +private: + YMacro() {} + ~YMacro() {} + +public: + + /** + * Set a macro recorder. + * + * This needs to be done from the outside since YMacroRecorder is an + * abstract base class, i.e., it needs to be derived to be instantiated. + **/ + static void setRecorder( YMacroRecorder * recorder ); + + /** + * Set a macro player. + * + * This needs to be done from the outside since YMacroRecorder is an + * abstract base class, i.e., it needs to be derived to be instantiated. + **/ + static void setPlayer( YMacroPlayer * player ); + + /** + * Record a macro to the specified macro file. + **/ + static void record( const std::string & macroFile ); + + /** + * End macro recording. + **/ + static void endRecording(); + + /** + * Return 'true' if a macro is currently being recorded. + **/ + static bool recording(); + + /** + * Play a macro from the specified macro file. + **/ + static void play( const std::string & macroFile ); + + /** + * Play the next block from the current macro, if there is one playing. + **/ + static void playNextBlock(); + + /** + * Return 'true' if a macro is currently being played. + **/ + static bool playing(); + + /** + * Return the current macro recorder or 0 if there is none. + **/ + static YMacroRecorder * recorder() { return _recorder; } + + /** + * Return the current macro player or 0 if there is none. + **/ + static YMacroPlayer * player() { return _player; } + + /** + * Delete the current macro recorder if there is one. + **/ + static void deleteRecorder(); + + /** + * Delete the current macro player if there is one. + **/ + static void deletePlayer(); + +private: + + static YMacroRecorder * _recorder; + static YMacroPlayer * _player; +}; + + + +#endif // YMacro_h diff --git a/src/YMacroPlayer.h b/src/YMacroPlayer.h new file mode 100644 index 0000000..4941679 --- /dev/null +++ b/src/YMacroPlayer.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMacroPlayer.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMacroPlayer_h +#define YMacroPlayer_h + +#include + +/** + * Abstract base class for macro player. + * + * Applications should not use this directly, but the static methods in YMacro. + **/ +class YMacroPlayer +{ + friend class YMacro; + +protected: + /** + * Constructor + **/ + YMacroPlayer() {} + +public: + /** + * Destructor + **/ + virtual ~YMacroPlayer() {} + + /** + * Play a macro from the specified macro file. + **/ + virtual void play( const std::string & macroFile ) = 0; + + /** + * Play the next block from the current macro, if there is one playing. + **/ + virtual void playNextBlock() = 0; + + /** + * Return 'true' if a macro is currently being played. + **/ + virtual bool playing() const = 0; +}; + +#endif // YMacroPlayer_h diff --git a/src/YMacroRecorder.h b/src/YMacroRecorder.h new file mode 100644 index 0000000..c072a20 --- /dev/null +++ b/src/YMacroRecorder.h @@ -0,0 +1,87 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMacroRecorder.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMacroRecorder_h +#define YMacroRecorder_h + +#include + +class YWidget; + + +/** + * Abstract base class for macro recorders. + * + * Applications should not use this directly, but the static methods in YMacro. + **/ +class YMacroRecorder +{ + friend class YMacro; + +protected: + + /** + * Constructor + **/ + YMacroRecorder() {} + +public: + /** + * Destructor + **/ + virtual ~YMacroRecorder() {} + + /** + * Start recording a macro to the specified file. + **/ + virtual void record( const std::string & macroFileName ) = 0; + + /** + * End recording and close the current macro file (if there is any). + **/ + virtual void endRecording() = 0; + + /** + * Return 'true' if a macro is currently being recorded. + **/ + virtual bool recording() const = 0; + + /** + * Record one widget property. + **/ + virtual void recordWidgetProperty( YWidget * widget, + const char * propertyName ) = 0; + + /** + * Record a "UI::MakeScreenShot()" statement. + * + * If 'enabled' is 'false', this statement will be commented out. + * If no file name is given, a default file name (with auto-increment) will + * be used. + **/ + virtual void recordMakeScreenShot( bool enabled = false, + const std::string & filename = std::string() ) = 0; +}; + +#endif // YMacroRecorder_h diff --git a/src/YMenuButton.cc b/src/YMenuButton.cc new file mode 100644 index 0000000..1ace071 --- /dev/null +++ b/src/YMenuButton.cc @@ -0,0 +1,264 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMenuButton.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YMenuButton.h" +#include "YMenuItem.h" +#include "YShortcut.h" + + +struct YMenuButtonPrivate +{ + YMenuButtonPrivate() + : nextSerialNo( 0 ) + {} + + int nextSerialNo; +}; + + + + +YMenuButton::YMenuButton( YWidget * parent, const std::string & label ) + : YSelectionWidget( parent, label, + false ) // enforceSingleSelection + , priv( new YMenuButtonPrivate() ) +{ + YUI_CHECK_NEW( priv ); +} + + +YMenuButton::~YMenuButton() +{ + // NOP +} + + +void +YMenuButton::addItems( const YItemCollection & itemCollection ) +{ + YSelectionWidget::addItems( itemCollection ); + resolveShortcutConflicts(); + rebuildMenuTree(); +} + + +void +YMenuButton::addItem( YItem * item ) +{ + YSelectionWidget::addItem( item ); + item->setIndex( ++(priv->nextSerialNo) ); + + if ( item->hasChildren() ) + assignUniqueIndex( item->childrenBegin(), item->childrenEnd() ); +} + + +void +YMenuButton::assignUniqueIndex( YItemIterator begin, YItemIterator end ) +{ + for ( YItemIterator it = begin; it != end; ++it ) + { + YItem * item = *it; + + item->setIndex( ++(priv->nextSerialNo) ); + + if ( item->hasChildren() ) + assignUniqueIndex( item->childrenBegin(), item->childrenEnd() ); + } +} + + +void +YMenuButton::deleteAllItems() +{ + YSelectionWidget::deleteAllItems(); + priv->nextSerialNo = 0; +} + + +YMenuItem * +YMenuButton::findMenuItem( int index ) +{ + return findMenuItem( index, itemsBegin(), itemsEnd() ); +} + + +YMenuItem * +YMenuButton::findMenuItem( int wantedIndex, YItemConstIterator begin, YItemConstIterator end ) +{ + for ( YItemConstIterator it = begin; it != end; ++it ) + { + YMenuItem * item = dynamic_cast (*it); + + if ( item ) + { + if ( item->index() == wantedIndex ) + return item; + + if ( item->hasChildren() ) + { + YMenuItem * result = findMenuItem( wantedIndex, item->childrenBegin(), item->childrenEnd() ); + + if ( result ) + return result; + } + } + } + + return 0; +} + +static void resolveShortcutsConflictFlat(YItemConstIterator begin, YItemConstIterator end) +{ + bool used[ sizeof( char ) << 8 ]; + for ( unsigned i=0; i < sizeof( char ) << 8; i++ ) + used[i] = false; + std::vector conflicts; + + for ( YItemConstIterator it = begin; it != end; ++it ) + { + YMenuItem * item = dynamic_cast (*it); + + if ( item ) + { + if ( item->hasChildren() ) + { + resolveShortcutsConflictFlat(item->childrenBegin(), item->childrenEnd() ); + } + + char shortcut = YShortcut::normalized(YShortcut::findShortcut(item->label())); + + if (shortcut == 0) + { + conflicts.push_back(item); + yuiMilestone() << "No or invalid shortcut found " << item->label() << std::endl; + } + else if (used[(unsigned)shortcut]) + { + conflicts.push_back(item); + yuiWarning() << "Conflicting shortcut found " << item->label() << std::endl; + } + else + { + used[(unsigned)shortcut] = true; + } + } + else + { + yuiWarning() << "non menu item used in call " << (*it)->label() << std::endl; + } + } + + // cannot use YShortcut directly as YItem is not YWidget + for(YMenuItem *i: conflicts) + { + std::string clean = YShortcut::cleanShortcutString(i->label()); + char new_c = 0; + + size_t index = 0; + for (; index < clean.size(); ++index) + { + char ch = YShortcut::normalized(clean[index]); + // ch is set to 0 by normalized if not valid + if (ch != 0 && !used[(unsigned)ch]) + { + new_c = ch; + used[(unsigned)ch] = true; + break; + } + } + + if (new_c != 0) + { + clean.insert(index, 1, YShortcut::shortcutMarker()); + yuiMilestone() << "New label used: " << clean << std::endl; + } + i->setLabel(clean); + } +} + +void +YMenuButton::resolveShortcutConflicts() +{ + resolveShortcutsConflictFlat(itemsBegin(), itemsEnd()); +} + + +const YPropertySet & +YMenuButton::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Label Label on the menu button + * @property itemList Items All menu items and submenus + * @property std::string IconPath Base path for icons (on menu items) + */ + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YMenuButton::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YMenuButton::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YMenuButton.h b/src/YMenuButton.h new file mode 100644 index 0000000..205e730 --- /dev/null +++ b/src/YMenuButton.h @@ -0,0 +1,191 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMenuButton.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMenuButton_h +#define YMenuButton_h + +#include "YSelectionWidget.h" +#include "YMenuItem.h" + +class YMenuItem; +class YMenuButtonPrivate; + + +/** + * MenuButton: Similar to PushButton, but with several actions: Upon clicking + * on a MenuButton (or activating it with the keyboard), a pop-up menu opens + * where the user can activate an action. Menu items in that pop-up menu can + * have submenus (that will pop up in separate pop-up menus). + * + * Internally, this widget is more similar to the Tree widget. The difference + * is that it does not keep a "selected" status, but triggers an action right + * away, just like a PushButton. Like PushButton, MenuButton sends an event + * right away when the user selects an item (clicks on a menu item or activates + * it with the keyboard). Items that have a submenu never send an event, they + * simply open their submenu when activated. + **/ +class YMenuButton : public YSelectionWidget +{ +protected: + /** + * Constructor. + * + * 'label' is the user-visible text on the button (not above it like all + * other SelectionWidgets). + **/ + YMenuButton( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YMenuButton(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YMenuButton"; } + + /** + * Rebuild the displayed menu tree from the internally stored YMenuItems. + * + * The application should call this (once) after all items have been added + * with addItem(). YMenuButton::addItems() calls this automatically. + * + * Derived classes are required to implement this. + **/ + virtual void rebuildMenuTree() = 0; + + /** + * Add multiple items. For some UIs, this can be more efficient than + * calling addItem() multiple times. This function also automatically calls + * resolveShortcutConflicts() and rebuildMenuTree() at the end. + * + * Derived classes can overwrite this function, but they should call this + * base class function at the end of the new implementation. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void addItems( const YItemCollection & itemCollection ); + + /** + * Add one item. This widget assumes ownership of the item object and will + * delete it in its destructor. + * + * This reimplementation will an index to the item that is unique for all + * items in this MenuButton. That index can be used later with + * findMenuItem() to find the item by that index. + * + * @note please do not forget to call after adding all elements + * #resolveShortcutConflicts and #rebuildMenuTree in this order. It is + * important to call it after all submenus are added otherwise it won't + * have proper shortcuts and won't be rendered. + * @see examples/MenuButton.cc. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void addItem( YItem * item_disown ); + + /** + * Delete all items. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void deleteAllItems(); + + /** + * Resolve keyboard shortcut conflicts: Change shortcuts of menu items if + * there are duplicates in the respective menu level. + * + * This has to be called after all items are added, but before rebuildMenuTree() + * (see above). YMenuButton::addItems() calls this automatically. + **/ + void resolveShortcutConflicts(); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + +protected: + + /** + * Recursively find the first menu item with the specified index. + * Returns 0 if there is no such item. + **/ + YMenuItem * findMenuItem( int index ); + + /** + * Recursively find the first menu item with the specified index + * from iterator 'begin' to iterator 'end'. + * + * Returns 0 if there is no such item. + **/ + YMenuItem * findMenuItem( int index, YItemConstIterator begin, YItemConstIterator end ); + + /** + * Alias for findMenuItem(). Reimplemented to ensure consistent behaviour + * with YSelectionWidget::itemAt(). + **/ + YMenuItem * itemAt( int index ) + { return findMenuItem( index ); } + +private: + + /** + * Assign a unique index to all items from iterator 'begin' to iterator 'end'. + **/ + void assignUniqueIndex( YItemIterator begin, YItemIterator end ); + + + ImplPtr priv; +}; + + +#endif // YMenuButton_h diff --git a/src/YMenuItem.h b/src/YMenuItem.h new file mode 100644 index 0000000..9778e3c --- /dev/null +++ b/src/YMenuItem.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMenuItem.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMenuItem_h +#define YMenuItem_h + +#include "YTreeItem.h" + + + +/** + * Item class for menu items. + **/ +class YMenuItem: public YTreeItem +{ +public: + /** + * Constructors for toplevel items. + **/ + YMenuItem( const std::string & label ) + : YTreeItem( label ) + {} + + YMenuItem( const std::string & label, + const std::string & iconName ) + : YTreeItem( label, iconName ) + {} + + /** + * Constructors for items that have a parent item. + * + * They will automatically register this item with the parent item. The + * parent assumes ownership of this item and will delete it in its (the + * parent's) destructor. + **/ + YMenuItem( YMenuItem * parent, + const std::string & label ) + : YTreeItem( parent, label ) + {} + + YMenuItem( YMenuItem * parent, + const std::string & label, + const std::string & iconName ) + : YTreeItem( parent, label, iconName ) + {} + + /** + * Destructor. + * + * This will delete all children. + **/ + virtual ~YMenuItem() {} + + + /** + * Returns this item's parent item or 0 if it is a toplevel item. + **/ + YMenuItem * parent() const + { return dynamic_cast ( YTreeItem::parent() ); } + + +private: + + // Disable unwanted base class methods + + bool isOpen() const { return false; } + void setOpen( bool ) {} +}; + + +#endif // YMenuItem_h diff --git a/src/YMultiLineEdit.cc b/src/YMultiLineEdit.cc new file mode 100644 index 0000000..8c92f64 --- /dev/null +++ b/src/YMultiLineEdit.cc @@ -0,0 +1,156 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMultiLineEdit.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YMultiLineEdit.h" + + +#define DEFAULT_VISIBLE_LINES 3 + + +struct YMultiLineEditPrivate +{ + YMultiLineEditPrivate( const std::string & label ) + : label( label ) + , inputMaxLength( -1 ) + , defaultVisibleLines( DEFAULT_VISIBLE_LINES ) + {} + + std::string label; + int inputMaxLength; + int defaultVisibleLines; +}; + + + + +YMultiLineEdit::YMultiLineEdit( YWidget * parent, const std::string & label ) + : YWidget( parent ) + , priv( new YMultiLineEditPrivate( label ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YMultiLineEdit::~YMultiLineEdit() +{ + // NOP +} + + +std::string YMultiLineEdit::label() const +{ + return priv->label; +} + + +void YMultiLineEdit::setLabel( const std::string & label ) +{ + priv->label = label; +} + + +int YMultiLineEdit::inputMaxLength() const +{ + return priv->inputMaxLength; +} + + +void YMultiLineEdit::setInputMaxLength( int len ) +{ + priv->inputMaxLength = len; +} + + +int YMultiLineEdit::defaultVisibleLines() const +{ + return priv->defaultVisibleLines; +} + + +void YMultiLineEdit::setDefaultVisibleLines( int newVisibleLines ) +{ + priv->defaultVisibleLines = newVisibleLines; +} + + +const YPropertySet & +YMultiLineEdit::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Value the MultiLineEdit text contents (with newlines) + * @property std::string Label caption above the MultiLineEdit + * @property integer InputMaxLength maximum number of input characters + */ + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_InputMaxLength, YIntegerProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YMultiLineEdit::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.stringVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_InputMaxLength ) setInputMaxLength( val.integerVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YMultiLineEdit::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_InputMaxLength ) return YPropertyValue( inputMaxLength() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YMultiLineEdit.h b/src/YMultiLineEdit.h new file mode 100644 index 0000000..c52a6ae --- /dev/null +++ b/src/YMultiLineEdit.h @@ -0,0 +1,184 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMultiLineEdit.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMultiLineEdit_h +#define YMultiLineEdit_h + +#include "YWidget.h" + +class YMultiLineEditPrivate; + +/** + * A multi-line plain-text area + **/ +class YMultiLineEdit : public YWidget +{ +protected: + /** + * Constructor. + **/ + YMultiLineEdit( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YMultiLineEdit(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YMultiLineEdit"; } + + /** + * Get the current value (the text entered by the user or set from the + * outside) of this MultiLineEdit. + * + * Derived classes are required to implement this. + **/ + virtual std::string value() = 0; + + /** + * Set the current value (the text entered by the user or set from the + * outside) of this MultiLineEdit. + * + * Derived classes are required to implement this. + **/ + virtual void setValue( const std::string & text ) = 0; + + /** + * Get the label (the caption above the MultiLineEdit). + **/ + std::string label() const; + + /** + * Set the label (the caption above the MultiLineEdit). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * The maximum input length, i.e., the maximum number of characters the + * user can enter. -1 means no limit. + **/ + int inputMaxLength() const; + + /** + * Set the maximum input length, i.e., the maximum number of characters the + * user can enter. -1 means no limit. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setInputMaxLength( int numberOfChars ); + + /** + * Return the number of input lines that are visible by default. + * + * This is what the widget would like to get (which will be reflected by + * preferredHeight() ), not what it currently actually has due to layout + * constraints. + **/ + int defaultVisibleLines() const; + + /** + * Set the number of input lines that are visible by default. + * + * This is what the widget would like to get (which will be reflected by + * preferredHeight() ), not what it currently actually has due to layout + * constraints. + * + * Notice that since a MultiLineEdit is stretchable in both dimensions, it + * might get more or less screen space, depending on the layout. This value + * is only meaningful if there are no other layout constraints. + * + * Changing this value will not trigger a re-layout. + * + * Derived classes can overwrite this function (but should call this base + * class function in the new function implementation), but it will normally + * be sufficient to query defaultVisibleLines() in preferredHeight(). + **/ + virtual void setDefaultVisibleLines( int newVisibleLines ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + +private: + + ImplPtr priv; +}; + + +#endif // YMultiLineEdit_h diff --git a/src/YMultiProgressMeter.cc b/src/YMultiProgressMeter.cc new file mode 100644 index 0000000..f8267c5 --- /dev/null +++ b/src/YMultiProgressMeter.cc @@ -0,0 +1,182 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMultiProgressMeter.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YMultiProgressMeter.h" + + +struct YMultiProgressMeterPrivate +{ + YMultiProgressMeterPrivate( YUIDimension dim, + const std::vector & maxValues ) + : dim( dim ) + , maxValues( maxValues ) + { + // Make currentValues as large as maxValues + // and initialize each element with 0 + currentValues = std::vector( maxValues.size(), 0.0 ); + } + + + YUIDimension dim; + std::vector maxValues; + std::vector currentValues; +}; + + + + +YMultiProgressMeter::YMultiProgressMeter( YWidget * parent, + YUIDimension dim, + const std::vector & maxValues ) + : YWidget( parent ) + , priv( new YMultiProgressMeterPrivate( dim, maxValues ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, dim == YD_HORIZ ); + setDefaultStretchable( YD_VERT, dim == YD_VERT ); +} + + +YMultiProgressMeter::~YMultiProgressMeter() +{ + // NOP +} + + +YUIDimension +YMultiProgressMeter::dimension() const +{ + return priv->dim; +} + + +bool YMultiProgressMeter::horizontal() const +{ + return priv->dim == YD_HORIZ; +} + + +bool YMultiProgressMeter::vertical() const +{ + return priv->dim == YD_VERT; +} + + +int YMultiProgressMeter::segments() const +{ + return (int) priv->maxValues.size(); +} + + +float YMultiProgressMeter::maxValue( int segment ) const +{ + YUI_CHECK_INDEX( segment, 0, (int) priv->maxValues.size() ); + + return priv->maxValues[ segment ]; +} + + +float YMultiProgressMeter::currentValue( int segment ) const +{ + YUI_CHECK_INDEX( segment, 0, (int) priv->currentValues.size() ); + + return priv->currentValues[ segment ]; +} + + +void YMultiProgressMeter::setCurrentValue( int segment, float value ) +{ + YUI_CHECK_INDEX( segment, 0, (int) priv->currentValues.size() ); + + if ( value < 0.0 ) // Allow -1 etc. as marker values + value = 0.0; + + if ( value > maxValue( segment ) ) // Don't complain (beware of rounding errors) + value = maxValue( segment ); + + priv->currentValues[ segment ] = value; +} + + +void YMultiProgressMeter::setCurrentValues( const std::vector & values ) +{ + for ( int i=0; i < (int) values.size(); i++ ) + { + setCurrentValue( i, values[i] ); + } + + doUpdate(); +} + + +const YPropertySet & +YMultiProgressMeter::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property list Values the current values for all segments + */ + propSet.add( YProperty( YUIProperty_Values, YOtherProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YMultiProgressMeter::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Values ) return false; // need special processing + else + { + YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special handling necessary +} + + +YPropertyValue +YMultiProgressMeter::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Values ) return YPropertyValue( YOtherProperty ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YMultiProgressMeter.h b/src/YMultiProgressMeter.h new file mode 100644 index 0000000..57c758d --- /dev/null +++ b/src/YMultiProgressMeter.h @@ -0,0 +1,173 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMultiProgressMeter.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMultiProgressMeter_h +#define YMultiProgressMeter_h + +#include "YWidget.h" +#include + +class YMultiProgressMeterPrivate; + + +/** + * MultiProgressMeter: Progress bar with several segments that can indicate + * progress individually. This is useful to display progress of several + * activities that might not necessarily all be done in sequence. + * + * A common example is installing packages from several CDs: Each CD would get + * a separate segment. Each segment's size would be proportional to the amount + * of data to be installed from that CD. This visualizes at the same time + * (a) how many CDs are involved + * (b) how much in proportion is to be expected from each CD + * (c) whether or not a specific CD is finished. + * + * Visual example (horizontal MultiProgressMeter): + * + * [=============...] [===] [......] [.] + * + * This corresponds to 4 CDs: + * + * CD #1: A lot of packages are to be installed from this CD, and a fair amount + * of those are already installed, but some are still missing. + * CD #2: Some packages were installed from this, but this CD is finished. + * CD #3: Quite some packages are to be installed from this CD. + * CD #4: Very few packages are to be installed from this CD. + * + * As can be seen from this simple example, this widget can visualize a lot of + * complex information at the same time in a very natural way. + * + * + * This is an optional widget, i.e. not all UIs support it. + **/ +class YMultiProgressMeter : public YWidget +{ +protected: + /** + * Constructor + **/ + YMultiProgressMeter( YWidget * parent, + YUIDimension dim, + const std::vector & maxValues ); + +public: + /** + * Destructor. + **/ + virtual ~YMultiProgressMeter(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YMultiProgressMeter"; } + + /** + * Return the orientation of the MultiProgressBar. + **/ + YUIDimension dimension() const; + + /** + * Return 'true' if the orientation is horizontal. + **/ + bool horizontal() const; + + /** + * Return 'true' if the orientation is vertical. + **/ + bool vertical() const; + + /** + * Return the number of segments. + **/ + int segments() const; + + /** + * Return the maximum value for the specified segment (counting from 0). + **/ + float maxValue( int segment ) const; + + /** + * Return the current value for the specified segment (counting from 0). + * If no value has been set yet, -1 is returned. + **/ + float currentValue( int segment ) const; + + /** + * Set the current value for the specified segment. + * This must be in the range 0..maxValue( segment ). + * + * Remember to call doUpdate() after all changed values are set! + **/ + void setCurrentValue( int segment, float value ); + + /** + * Set all current values and call doUpdate(). + **/ + void setCurrentValues( const std::vector & values ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Notification that values have been updated and the widget needs to be + * redisplayed. Derived classes need to reimplement this. + **/ + virtual void doUpdate() = 0; + + +private: + + ImplPtr priv; + +}; + + +#endif // YMultiProgressMeter_h diff --git a/src/YMultiSelectionBox.cc b/src/YMultiSelectionBox.cc new file mode 100644 index 0000000..4790c07 --- /dev/null +++ b/src/YMultiSelectionBox.cc @@ -0,0 +1,143 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YMultiSelectionBox.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YMultiSelectionBox.h" +#include "YUISymbols.h" +#include "YMacroRecorder.h" +#include "YUIException.h" + + +struct YMultiSelectionBoxPrivate +{ + YMultiSelectionBoxPrivate() + : shrinkable( false ) + {} + + bool shrinkable; +}; + + + +YMultiSelectionBox::YMultiSelectionBox( YWidget * parent, const std::string & label ) + : YSelectionWidget( parent, label, + false ) // enforceSingleSelection + , priv( new YMultiSelectionBoxPrivate ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); + +} + + +YMultiSelectionBox::~YMultiSelectionBox() +{ + // NOP +} + + +bool YMultiSelectionBox::shrinkable() const +{ + return priv->shrinkable; +} + + +void YMultiSelectionBox::setShrinkable( bool shrinkable ) +{ + priv->shrinkable = shrinkable; +} + + +const YPropertySet & +YMultiSelectionBox::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property itemList SelectedItems All currently selected items + * @property itemList Items All items + * @property itemID CurrentItem The current item (no matter if selected or not) + * @property std::string Label Caption above the MultiSelectionBox + */ + propSet.add( YProperty( YUIProperty_CurrentItem, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_SelectedItems, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YMultiSelectionBox::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_CurrentItem ) return false; // Needs special handling + else if ( propertyName == YUIProperty_SelectedItems ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YMultiSelectionBox::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_CurrentItem ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_SelectedItems ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} + + + +void +YMultiSelectionBox::saveUserInput( YMacroRecorder *macroRecorder ) +{ + macroRecorder->recordWidgetProperty( this, YUIProperty_CurrentItem ); + macroRecorder->recordWidgetProperty( this, YUIProperty_SelectedItems ); +} diff --git a/src/YMultiSelectionBox.h b/src/YMultiSelectionBox.h new file mode 100644 index 0000000..bbe5a20 --- /dev/null +++ b/src/YMultiSelectionBox.h @@ -0,0 +1,144 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSelectionBox.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YMultiSelectionBox_h +#define YMultiSelectionBox_h + +#include "YSelectionWidget.h" + +class YMultiSelectionBoxPrivate; + + +/** + * A variant of YSelectionBox where more than one item can be selected. + **/ +class YMultiSelectionBox : public YSelectionWidget +{ +protected: + /** + * Constructor. + **/ + YMultiSelectionBox( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YMultiSelectionBox(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YMultiSelectionBox"; } + + /** + * Return 'true' if this MultiSelectionBox should be very small. + **/ + bool shrinkable() const; + + /** + * Make this MultiSelectionBox very small. This will take effect only upon + * the next geometry management run. + * + * Derived classes can overwrite this, but should call this base class + * function in the new function. + **/ + virtual void setShrinkable( bool shrinkable = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_SelectedItems; } + + /** + * Return the the item that currently has the keyboard focus + * or 0 if no item currently has the keyboard focus. + * + * Notice that for a MultiSelectionBox the current item is not necessarily + * selected, i.e., its check box may or may not be checked. + * + * Derived classes are required to implement this function. + **/ + virtual YItem * currentItem() = 0; + + /** + * Set the keyboard focus to the specified item. + * 0 means clear the keyboard focus. + * + * Notice that for a MultiSelectionBox the current item is not necessarily + * selected, i.e., its check box may or may not be checked. + * Use selectItem() for that. + * + * Also notice that selectItem() does not make that newly selected item the + * current item. + * + * Derived classes are required to implement this function. + **/ + virtual void setCurrentItem( YItem * item ) = 0; + + /** + * Save the widget's user input to a macro recorder. + * + * Reimplemented from YWidget because two properties need to be recorded. + **/ + virtual void saveUserInput( YMacroRecorder *macroRecorder ); + +private: + + ImplPtr priv; +}; + + +#endif // YMultiSelectionBox_h diff --git a/src/YOptionalWidgetFactory.cc b/src/YOptionalWidgetFactory.cc new file mode 100644 index 0000000..e4cddf2 --- /dev/null +++ b/src/YOptionalWidgetFactory.cc @@ -0,0 +1,282 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YOptionalWidgetFactory.cc + + Author: Stefan Hundhammer + +/-*/ + +#include "YOptionalWidgetFactory.h" +#include "YWidgetFactory.h" +#include "YUIException.h" +#include "YLabel.h" +#include "YUI.h" + +#define YUILogComponent "owf" +#include "YUILog.h" + + +#define THROW_UNSUPPORTED( WIDGET_TYPE ) \ + YUI_THROW( YUIUnsupportedWidgetException( WIDGET_TYPE ) ); \ + return 0 + + + +YOptionalWidgetFactory::YOptionalWidgetFactory() +{ + // NOP +} + +YOptionalWidgetFactory::~YOptionalWidgetFactory() +{ + // NOP + yuiMilestone() << "YOptionalWidgetFactory removed" << std::endl; + +} + + + +bool YOptionalWidgetFactory::hasWizard() +{ + return false; +} + +YWizard * +YOptionalWidgetFactory::createWizard( YWidget * parent, + const std::string & backButtonLabel, + const std::string & abortButtonLabel, + const std::string & nextButtonLabel, + YWizardMode wizardMode ) +{ + THROW_UNSUPPORTED( "YWizard" ); +} + + + +bool YOptionalWidgetFactory::hasDumbTab() +{ + return false; +} + +YDumbTab * +YOptionalWidgetFactory::createDumbTab( YWidget * parent ) +{ + THROW_UNSUPPORTED( "YDumbTab" ); +} + + + +bool YOptionalWidgetFactory::hasSlider() +{ + return false; +} + +YSlider * +YOptionalWidgetFactory::createSlider( YWidget * parent, + const std::string & label, + int minVal, + int maxVal, + int initialVal ) +{ + THROW_UNSUPPORTED( "YSlider" ); +} + + + +bool YOptionalWidgetFactory::hasDateField() +{ + return false; +} + +YDateField * +YOptionalWidgetFactory::createDateField( YWidget * parent, const std::string & label ) +{ + THROW_UNSUPPORTED( "YDateField" ); +} + + + +bool YOptionalWidgetFactory::hasTimeField() +{ + return false; +} + +YTimeField * +YOptionalWidgetFactory::createTimeField( YWidget * parent, const std::string & label ) +{ + THROW_UNSUPPORTED( "YTimeField" ); +} + + + +bool YOptionalWidgetFactory::hasBarGraph() +{ + return false; +} + +YBarGraph * +YOptionalWidgetFactory::createBarGraph( YWidget * parent ) +{ + THROW_UNSUPPORTED( "YBarGraph" ); +} + + + +bool YOptionalWidgetFactory::hasPatternSelector() +{ + return false; +} + +YWidget * +YOptionalWidgetFactory::createPatternSelector( YWidget * parent, long modeFlags ) +{ + THROW_UNSUPPORTED( "YPatternSelector" ); +} + + + +bool YOptionalWidgetFactory::hasSimplePatchSelector() +{ + return false; +} + +YWidget * +YOptionalWidgetFactory::createSimplePatchSelector( YWidget * parent, long modeFlags ) +{ + THROW_UNSUPPORTED( "YSimplePatchSelector" ); +} + + + +bool YOptionalWidgetFactory::hasMultiProgressMeter() +{ + return false; +} + +YMultiProgressMeter * +YOptionalWidgetFactory::createMultiProgressMeter( YWidget * parent, YUIDimension dim, const std::vector & maxValues ) +{ + THROW_UNSUPPORTED( "YMultiProgressMeter" ); +} + +YMultiProgressMeter * +YOptionalWidgetFactory::createHMultiProgressMeter( YWidget * parent, const std::vector & maxValues ) +{ + return createMultiProgressMeter( parent, YD_HORIZ, maxValues ); +} + +YMultiProgressMeter * +YOptionalWidgetFactory::createVMultiProgressMeter( YWidget * parent, const std::vector & maxValues ) +{ + return createMultiProgressMeter( parent, YD_VERT, maxValues ); +} + + + +bool YOptionalWidgetFactory::hasPartitionSplitter() +{ + return false; +} + +YPartitionSplitter * +YOptionalWidgetFactory::createPartitionSplitter( YWidget * parent, + int usedSize, + int totalFreeSize, + int newPartSize, + int minNewPartSize, + int minFreeSize, + const std::string & usedLabel, + const std::string & freeLabel, + const std::string & newPartLabel, + const std::string & freeFieldLabel, + const std::string & newPartFieldLabel ) +{ + THROW_UNSUPPORTED( "YPartitionSplitter" ); +} + + + +bool YOptionalWidgetFactory::hasDownloadProgress() +{ + return false; +} + +YDownloadProgress * +YOptionalWidgetFactory::createDownloadProgress( YWidget * parent, + const std::string & label, + const std::string & filename, + YFileSize_t expectedFileSize ) +{ + THROW_UNSUPPORTED( "YDownloadProgress" ); +} + + + +bool YOptionalWidgetFactory::hasDummySpecialWidget() +{ + return true; +} + +YWidget * +YOptionalWidgetFactory::createDummySpecialWidget( YWidget * parent ) +{ + return YUI::widgetFactory()->createOutputField( parent, "YDummySpecialWidget" ); +} + +bool YOptionalWidgetFactory::hasTimezoneSelector() +{ + return false; +} + +YTimezoneSelector * +YOptionalWidgetFactory::createTimezoneSelector( YWidget * parent, + const std::string & _map, + const std::map& zones) +{ + THROW_UNSUPPORTED( "YTimezoneSelector" ); +} + + +bool +YOptionalWidgetFactory::hasGraph() +{ + return false; +} + + +YGraph * +YOptionalWidgetFactory::createGraph( YWidget * parent, const std::string & filename, + const std::string & layoutAlgorithm ) +{ + THROW_UNSUPPORTED( "YGraph" ); +} + + +YGraph * +YOptionalWidgetFactory::createGraph( YWidget * parent, /* graph_t */ void * graph ) +{ + THROW_UNSUPPORTED( "YGraph" ); +} + + +bool +YOptionalWidgetFactory::hasContextMenu() +{ + return false; +} diff --git a/src/YOptionalWidgetFactory.h b/src/YOptionalWidgetFactory.h new file mode 100644 index 0000000..f753911 --- /dev/null +++ b/src/YOptionalWidgetFactory.h @@ -0,0 +1,156 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YOptionalWidgetFactory.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YOptionalWidgetFactory_h +#define YOptionalWidgetFactory_h + +#include +#include +#include + +#include "YTypes.h" +#include "YWizard.h" +#include "YGraph.h" + + +class YBarGraph; +class YDateField; +class YDownloadProgress; +class YDumbTab; +class YDummySpecialWidget; +class YMultiProgressMeter; +class YPartitionSplitter; +class YSlider; +class YTimeField; +class YWidget; +class YTimezoneSelector; + +/** + * Abstract widget factory for optional ("special") widgets. + * + * Remember to always check with the corresponding "has..()" method if the + * current UI actually provides the requested widget. Otherwise the + * "create...()" method will throw an exception. + **/ +class YOptionalWidgetFactory +{ +public: + + // + // Optional Widgets + // + + virtual bool hasWizard(); + virtual YWizard * createWizard ( YWidget * parent, + const std::string & backButtonLabel, + const std::string & abortButtonLabel, + const std::string & nextButtonLabel, + YWizardMode wizardMode = YWizardMode_Standard ); + + virtual bool hasDumbTab(); + virtual YDumbTab * createDumbTab ( YWidget * parent ); + + virtual bool hasSlider(); + virtual YSlider * createSlider ( YWidget * parent, + const std::string & label, + int minVal, + int maxVal, + int initialVal ); + + virtual bool hasDateField(); + virtual YDateField * createDateField ( YWidget * parent, const std::string & label ); + + virtual bool hasTimeField(); + virtual YTimeField * createTimeField ( YWidget * parent, const std::string & label ); + + virtual bool hasBarGraph(); + virtual YBarGraph * createBarGraph ( YWidget * parent ); + + virtual bool hasPatternSelector(); + virtual YWidget * createPatternSelector ( YWidget * parent, long modeFlags = 0 ); + + virtual bool hasSimplePatchSelector(); + virtual YWidget * createSimplePatchSelector( YWidget * parent, long modeFlags = 0 ); + + virtual bool hasMultiProgressMeter(); + YMultiProgressMeter * createHMultiProgressMeter( YWidget * parent, const std::vector & maxValues ); + YMultiProgressMeter * createVMultiProgressMeter( YWidget * parent, const std::vector & maxValues ); + virtual YMultiProgressMeter * createMultiProgressMeter ( YWidget * parent, YUIDimension dim, const std::vector & maxValues ); + + virtual bool hasPartitionSplitter(); + virtual YPartitionSplitter * createPartitionSplitter ( YWidget * parent, + int usedSize, + int totalFreeSize, + int newPartSize, + int minNewPartSize, + int minFreeSize, + const std::string & usedLabel, + const std::string & freeLabel, + const std::string & newPartLabel, + const std::string & freeFieldLabel, + const std::string & newPartFieldLabel ); + + + virtual bool hasDownloadProgress(); + virtual YDownloadProgress * createDownloadProgress ( YWidget * parent, + const std::string & label, + const std::string & filename, + YFileSize_t expectedFileSize ); + + bool hasDummySpecialWidget(); + YWidget * createDummySpecialWidget( YWidget * parent ); + + virtual bool hasTimezoneSelector(); + virtual YTimezoneSelector * createTimezoneSelector( YWidget * parent, + const std::string & pixmap, + const std::map & timezones ); + + virtual bool hasGraph(); + virtual YGraph * createGraph( YWidget * parent, const std::string & filename, + const std::string & layoutAlgorithm ); + virtual YGraph * createGraph( YWidget * parent, /* graph_t */ void * graph ); + + virtual bool hasContextMenu(); + +protected: + + friend class YUI; + + /** + * Constructor. + * + * Use YUI::optionalWidgetFactory() to get the singleton for this class. + **/ + YOptionalWidgetFactory(); + + /** + * Destructor. + **/ + virtual ~YOptionalWidgetFactory(); + +}; // class YOptionalWidgetFactory + + + +#endif // YOptionalWidgetFactory_h diff --git a/src/YPackageSelector.cc b/src/YPackageSelector.cc new file mode 100644 index 0000000..7996fa7 --- /dev/null +++ b/src/YPackageSelector.cc @@ -0,0 +1,40 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YPackageSelector.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui-pkg" +#include "YUILog.h" + +#include "YPackageSelector.h" + + +YPackageSelector::YPackageSelector( YWidget * parent, long modeFlags ) + : YWidget( parent ) + , _modeFlags( modeFlags ) +{ + yuiMilestone() << "YPackageSelector flags: " << std::hex << modeFlags << std::dec << std::endl; + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} diff --git a/src/YPackageSelector.h b/src/YPackageSelector.h new file mode 100644 index 0000000..e0efd4c --- /dev/null +++ b/src/YPackageSelector.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YPackageSelector.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YPackageSelector_h +#define YPackageSelector_h + +#include "YWidget.h" + +#define YPkg_TestMode 1 << 0 // Test mode for debugging +#define YPkg_OnlineUpdateMode 1 << 1 // Online update mode: Show patches +#define YPkg_UpdateMode 1 << 2 // Start with "Update problems" filter view +#define YPkg_SearchMode 1 << 3 // Start with "Search" filter view +#define YPkg_SummaryMode 1 << 4 // Start with "Summary" filter view +#define YPkg_RepoMode 1 << 5 // Start with "Repositories" filter view +#define YPkg_RepoMgr 1 << 6 // Add "Manage Repositories" to menu +#define YPkg_ConfirmUnsupported 1 << 7 // Confirm unsupported packages + +/** + * A simple wrapper for an insanely complex UI for installing software. + **/ +class YPackageSelector : public YWidget +{ +protected: + /** + * Constructor. + * + * 'modeFlags' are flags determining which modes to use, ORed together: + * YPkg_OnlineUpdateMode | YPkg_TestMode + **/ + YPackageSelector( YWidget * parent, long modeFlags = 0 ); + +public: + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YPackageSelector"; } + + /** + * Check for the various modes. + **/ + bool testMode() const { return _modeFlags & YPkg_TestMode; } + bool onlineUpdateMode() const { return _modeFlags & YPkg_OnlineUpdateMode; } + bool updateMode() const { return _modeFlags & YPkg_UpdateMode; } + bool searchMode() const { return _modeFlags & YPkg_SearchMode; } + bool summaryMode() const { return _modeFlags & YPkg_SummaryMode; } + bool repoMode() const { return _modeFlags & YPkg_RepoMode; } + bool repoMgrEnabled() const { return _modeFlags & YPkg_RepoMgr; } + bool confirmUnsupported() const { return _modeFlags & YPkg_ConfirmUnsupported; } + +protected: + long _modeFlags; +}; + + +#endif // YPackageSelector_h diff --git a/src/YPackageSelectorPlugin.h b/src/YPackageSelectorPlugin.h new file mode 100644 index 0000000..7336f5b --- /dev/null +++ b/src/YPackageSelectorPlugin.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YPackageSelectorPlugin.h + + Author: Stefan Hundhammer + +/-*/ + + +#ifndef YPackageSelectorPlugin_h +#define YPackageSelectorPlugin_h + +#include "YUIPlugin.h" + +class YWidget; +class YPackageSelector; + + +/** + * Abstract base class for simplified access to UI plugins for package selection. + **/ +class YPackageSelectorPlugin: public YUIPlugin +{ +protected: + /** + * Constructor: Load the specified plugin library + * from the standard UI plugin directory (/usr/lib/yui/). + **/ + YPackageSelectorPlugin( const char * pluginLibBaseName ) + : YUIPlugin( pluginLibBaseName ) {} + + /** + * Destructor. Calls dlclose() which will unload the plugin library if it + * is no longer used, i.e. if the reference count dlopen() uses reaches 0. + **/ + virtual ~YPackageSelectorPlugin() {} + +public: + /** + * Create a package selector. + * Derived classes need to implement this. + * + * This might return 0 if the plugin lib could not be loaded or if the + * appropriate symbol could not be located in the plugin lib. + **/ + virtual YPackageSelector * createPackageSelector( YWidget * parent, long modeFlags = 0 ) = 0; +}; + + +#endif // YPackageSelectorPlugin_h diff --git a/src/YPartitionSplitter.cc b/src/YPartitionSplitter.cc new file mode 100644 index 0000000..7dd8488 --- /dev/null +++ b/src/YPartitionSplitter.cc @@ -0,0 +1,202 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YPartitionSplitter.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YPartitionSplitter.h" + + +struct YPartitionSplitterPrivate +{ + YPartitionSplitterPrivate( int usedSize, + int totalFreeSize, + int minNewPartSize, + int minFreeSize, + const std::string & usedLabel, + const std::string & freeLabel, + const std::string & newPartLabel, + const std::string & freeFieldLabel, + const std::string & newPartFieldLabel ) + : usedSize ( usedSize ) + , totalFreeSize ( totalFreeSize ) + , minNewPartSize ( minNewPartSize ) + , minFreeSize ( minFreeSize ) + , usedLabel ( usedLabel ) + , freeLabel ( freeLabel ) + , newPartLabel ( newPartLabel ) + , freeFieldLabel ( freeFieldLabel ) + , newPartFieldLabel ( newPartFieldLabel ) + {} + + int usedSize; + int totalFreeSize; + int minNewPartSize; + int minFreeSize; + std::string usedLabel; + std::string freeLabel; + std::string newPartLabel; + std::string freeFieldLabel; + std::string newPartFieldLabel; +}; + + + + +YPartitionSplitter::YPartitionSplitter( YWidget * parent, + int usedSize, + int totalFreeSize, + int newPartSize, + int minNewPartSize, + int minFreeSize, + const std::string & usedLabel, + const std::string & freeLabel, + const std::string & newPartLabel, + const std::string & freeFieldLabel, + const std::string & newPartFieldLabel ) + : YWidget( parent ) + , priv( new YPartitionSplitterPrivate( usedSize, + totalFreeSize, + minNewPartSize, + minFreeSize, + usedLabel, + freeLabel, + newPartLabel, + freeFieldLabel, + newPartFieldLabel ) + ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setStretchable( YD_VERT, false ); +} + + +YPartitionSplitter::~YPartitionSplitter() +{ + // NOP +} + + +int YPartitionSplitter::usedSize() const +{ + return priv->usedSize; +} + + +int YPartitionSplitter::totalFreeSize() const +{ + return priv->totalFreeSize; +} + + +int YPartitionSplitter::minNewPartSize() const +{ + return priv->minNewPartSize; +} + + +int YPartitionSplitter::minFreeSize() const +{ + return priv->minFreeSize; +} + + +std::string YPartitionSplitter::usedLabel() const +{ + return priv->usedLabel; +} + + +std::string YPartitionSplitter::freeLabel() const +{ + return priv->freeLabel; +} + + +std::string YPartitionSplitter::newPartLabel() const +{ + return priv->newPartLabel; +} + + +std::string YPartitionSplitter::freeFieldLabel() const +{ + return priv->freeFieldLabel; +} + + +std::string YPartitionSplitter::newPartFieldLabel() const +{ + return priv->newPartFieldLabel; +} + + +const YPropertySet & +YPartitionSplitter::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Value the value (the size of the new partition) + */ + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YPartitionSplitter::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.integerVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YPartitionSplitter::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YPartitionSplitter.h b/src/YPartitionSplitter.h new file mode 100644 index 0000000..2839bbc --- /dev/null +++ b/src/YPartitionSplitter.h @@ -0,0 +1,190 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YPartitionSplitter.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YPartitionSplitter_h +#define YPartitionSplitter_h + +#include "YWidget.h" + + +class YPartitionSplitterPrivate; + + +/** + * PartitionSplitter: A (very custom) widget for easily splitting one existing + * partition into two. + * + * Layout: + * + * +--------------------+---------------+--------------------------+ + * | Old Partition | Old Partition | New Partition | + * | used | free | | + * +--------------------+---------------+--------------------------+ + * + * Old Partition free New Partition + * [ 123 ] ================O================================ [ 123 ] + * + * + * At the top, there is a BarGraph that dynamicylla displays the sizes in + * graphical form. Below are an IntField to the left and an IntField to the + * right, each with its respective label. Between the two IntFields there is a + * Slider. + * + * The user can enter a value in either IntField or drag the slider. The other + * sub-widgets (including the BarGraph) will automatically be + * adjusted. Visually (in the BarGraph), the border between "old partition + * free" and "new partition" will move left and right. The border between "old + * partition used" and "old partition free" is static. + * + * There are built-in (configurable) limits for the minimum sizes of "old + * partition free" and "new partition". + **/ +class YPartitionSplitter : public YWidget +{ +protected: + /** + * Constructor. + * + * usedSize: Used size of the old partition (constant) + * + * totalFreeSize: Total free size of the old partition before the split: + * OldPartitionFree + NewPartition + * + * newPartSize': Initial size of the new partition + * + * minNewPartSize: Miminum size of the new partition + * + * minFreeSize: Minimum free size of the old partition + * + * usedLabel: BarGraph label for the used part of the old partition + * + * freeLabel: BarGraph label for the free part of the old partition + * + * newPartLabel: BarGraph label for the new partition + * + * freeFieldLabel: IntField label for the free part of the old partition + * + * newPartFieldLabel: IntField label for the size of the new partition + **/ + YPartitionSplitter( YWidget * parent, + int usedSize, + int totalFreeSize, + int newPartSize, + int minNewPartSize, + int minFreeSize, + const std::string & usedLabel, + const std::string & freeLabel, + const std::string & newPartLabel, + const std::string & freeFieldLabel, + const std::string & newPartFieldLabel ); + +public: + + /** + * Destructor. + **/ + virtual ~YPartitionSplitter(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YPartitionSplitter"; } + + /** + * The value of this PartitionSplitter: The size of the new partition. + * + * Derived classes are required to implement this. + **/ + virtual int value() = 0; + + /** + * Set the value (the size of the new partition). + * + * Derived classes are required to implement this. + **/ + virtual void setValue( int newValue ) = 0; + + + // Access methods + + int usedSize() const; + int totalFreeSize() const; + int minFreeSize() const; + int maxFreeSize() const { return totalFreeSize() - minNewPartSize(); } + int freeSize() { return totalFreeSize() - newPartSize(); } + int newPartSize() { return value(); } + int minNewPartSize() const; + int maxNewPartSize() const { return totalFreeSize() - minFreeSize(); } + + std::string usedLabel() const; + std::string freeLabel() const; + std::string newPartLabel() const; + std::string freeFieldLabel() const; + std::string newPartFieldLabel() const; + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + +private: + + ImplPtr priv; +}; + + +#endif // YPartitionSplitter_h diff --git a/src/YPath.cc b/src/YPath.cc new file mode 100644 index 0000000..767399f --- /dev/null +++ b/src/YPath.cc @@ -0,0 +1,179 @@ +/* + Copyright (c) 2012 Björn Esser + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +/*-/ + + File: YPath.cc + + Author: Björn Esser + +/-*/ + +#include +#include +#include +#include +#include +#include + +#include "YPath.h" +#include "YSettings.h" +#include "Libyui_config.h" + +#define YUILogComponent "ui" +#include "YUILog.h" + +YPath::YPath ( const std::string & directory, const std::string & filename ) +{ + yuiMilestone () << "Given filename: " << filename << std::endl; + + bool isThemeDir = ! directory.compare ( THEMEDIR ); + std::string progSubDir = YSettings::progDir (); + std::string fullname = ""; + std::string themeSubDir = "/current"; + size_t splitPos = fullPath.rfind( "/" ); + bool hasProgSubDir = progSubDir.compare ( "" ); + bool hasSubDirPrepend = ( splitPos != std::string::npos ); + std::string filenameNoPrepend = filename.substr ( splitPos + 1, std::string::npos ); + std::string subDirPrepend = ""; + std::vector dirList; + + if ( hasSubDirPrepend ) + subDirPrepend = filename.substr ( 0, splitPos ); + + yuiMilestone () << "Preferring subdir: " << progSubDir << std::endl; + yuiMilestone () << "Subdir given with filename: " << subDirPrepend << std::endl; + yuiMilestone () << "Looking for: " << filenameNoPrepend << std::endl; + + if ( hasSubDirPrepend ) // prefer subdir prepended to filename + { + if ( isThemeDir ) // prefer /current inside THEMEDIR + { + if ( hasProgSubDir ) + dirList.push_back ( directory + "/" + progSubDir + themeSubDir + "/" + subDirPrepend ); + + dirList.push_back ( directory + themeSubDir + "/" + subDirPrepend ); + } + if ( hasProgSubDir ) + dirList.push_back ( directory + "/" + progSubDir + "/" + subDirPrepend ); + + dirList.push_back ( directory + "/" + subDirPrepend ); + } + + if ( isThemeDir ) // prefer /current inside THEMEDIR + { + if ( hasProgSubDir ) + dirList.push_back ( directory + "/" + progSubDir + themeSubDir ); + + dirList.push_back ( directory + themeSubDir ); + } + + // the "usual" lookup + if ( hasProgSubDir ) + dirList.push_back ( directory + "/" + progSubDir ); + + dirList.push_back ( directory ); + + for ( std::vector::const_iterator x = dirList.begin () ; x != dirList.end () && fullPath.compare ( "" ) == 0 ; ++x ) + { + std::vector fileList = lsDir( *x ); + + for ( std::vector::const_iterator i = fileList.begin () ; i != fileList.end () && fullPath.compare ( "" ) == 0 ; ++i ) + { + if ( *i != "." && *i != ".." ) // filter out parent and curdir + { + fullname = directory + "/" + *i; + if ( *i == filenameNoPrepend ) + fullPath = fullname; + else + { + fullPath = lookRecursive ( fullname, filenameNoPrepend ); + } + } + } + } + + if( fullPath.compare ( "" ) != 0 ) + yuiMilestone() << "Found " << filenameNoPrepend << " in " << dir() << std::endl; + else + { + yuiMilestone() << "Could NOT find " << filename << " by looking recursive inside " << directory << std::endl; + fullPath = filename; + } +} + +YPath::~YPath() +{ +} + +std::vector YPath::lsDir( const std::string & directory ) +{ + std::vector fileList; + DIR * dir; + struct dirent * ent; + + if ( ( dir = opendir( directory.c_str () ) ) != NULL ) + { + yuiMilestone() << "Looking in " << directory << std::endl; + + while ( ( ent = readdir ( dir ) ) != NULL ) + fileList.push_back ( ent -> d_name ); + + closedir ( dir ); + } + + return fileList; +} + +std::string YPath::lookRecursive( const std::string & directory, const std::string & filename ) +{ + std::vector fileList = lsDir( directory ); + std::string file = ""; + std::string fullname; + + for ( std::vector::const_iterator i = fileList.begin() ; i != fileList.end() && file.compare ( "" ) == 0 ; ++i ) + { + if ( *i != "." && *i != ".." ) // filter out parent and curdir + { + fullname = directory + "/" + ( *i ); + if ( *i == filename ) + file = fullname; + else + { + file = lookRecursive ( fullname, filename ); + } + } + } + return file; +} + +std::string YPath::path() +{ + return fullPath; +} + +std::string YPath::dir() +{ + return fullPath.substr ( 0, fullPath.rfind( "/" ) ); +} diff --git a/src/YPath.h b/src/YPath.h new file mode 100644 index 0000000..7ddc8c3 --- /dev/null +++ b/src/YPath.h @@ -0,0 +1,81 @@ +/* + Copyright (c) 2012 Björn Esser + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +/*-/ + + File: YPath.h + + Author: Björn Esser + +/-*/ + +#ifndef YPath_h +#define YPath_h + +#include +#include + +/** + * Finds files (e.g. plugins or theme pixmaps) recursively inside + * a directory. + **/ +class YPath +{ + +public: + +/** + * Constructor + * + * to be called with the directory where to look inside + * and filename which to lookup. + * + * YSettings::progSubDir will be preferred by the lookup. + **/ + YPath( const std::string & directory, const std::string & filename ); +/** + * Destructor + **/ + ~YPath(); +/** + * Returns the full path of the file if found; + * if not found just the filename given in constructor. + **/ + std::string path(); +/** + * Returns the directory where the file is found; + * if not found just the subdir part (if there's any) of + * the filename given in constructor. + **/ + std::string dir(); + +private: + + std::vector lsDir( const std::string & directory ); + std::string lookRecursive( const std::string & directory, const std::string & filename ); + std::string fullPath; + +}; + +#endif // YUIDIRFINDER_H diff --git a/src/YPopupInternal.cc b/src/YPopupInternal.cc new file mode 100644 index 0000000..251fb4a --- /dev/null +++ b/src/YPopupInternal.cc @@ -0,0 +1,147 @@ +/* + Copyright (C) 2016 SUSE LLC + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define YUILogComponent "ui-popup" +#include "YUILog.h" + +#include + +void YPopupInternal::message(const std::string &label) +{ + auto f = YUI::widgetFactory(); + + auto popup = f->createPopupDialog(); + auto mb = f->createMarginBox(popup, 1, 0.1); + auto vbox = f->createVBox(mb); + f->createLabel(vbox, label); + + auto bbox = f->createButtonBox(vbox); + auto okButton = f->createPushButton(bbox, "OK"); + okButton->setRole(YOKButton); + okButton->setDefaultButton(); + + while (true) + { + auto event = popup->waitForEvent(); + if (event && (event->widget() == okButton || event->eventType() == YEvent::CancelEvent)) + { + break; + } + } + + popup->destroy(); +} + +/** + * Helper method for adding new input fields + * @param parent Where to add the widget + * @param val The initial value + */ +static void addTextField(YWidget *parent, const std::string &val) +{ + auto new_item = YUI::widgetFactory()->createInputField(parent, ""); + new_item->setProperty("Value", YPropertyValue(val)); + new_item->setProperty("HStretch", YPropertyValue(true)); +} + +bool YPopupInternal::editStringArray(StringArray &array, const std::string &label) +{ + auto f = YUI::widgetFactory(); + + auto popup = f->createPopupDialog(); + auto mb = f->createMarginBox(popup, 1, 0.1); + auto vbox = f->createVBox(mb); + f->createHeading(vbox, label); + YWidget *arrayBox = f->createVBox(vbox); + + // access by reference + for(auto&& str: array) addTextField(arrayBox, str); + + auto addButton = f->createPushButton(vbox, "Add Item"); + + auto spacing = f->createVSpacing(vbox, 1); + spacing->setProperty("VStretch", YPropertyValue(true)); + + auto bbox = f->createButtonBox(vbox); + auto okButton = f->createPushButton(bbox, "OK"); + okButton->setRole(YOKButton); + okButton->setDefaultButton(); + auto cancelButton = f->createPushButton(bbox, "Cancel"); + cancelButton->setRole(YCancelButton); + + bool ret; + + while (true) + { + auto event = popup->waitForEvent(); + + if (!event) continue; + + // cancel button or the window manager close button + if (event->widget() == cancelButton || event->eventType() == YEvent::CancelEvent) + { + ret = false; + break; + } + else if (event->widget() == okButton) + { + array.clear(); + + // put all input field values into the target array + for(auto&& widget: *arrayBox) + { + auto input = dynamic_cast(widget); + if (input) array.push_back(input->value()); + } + + ret = true; + break; + } + else if (event->widget() == addButton) + { + addTextField(arrayBox, ""); + popup->recalcLayout(); + } + else + yuiWarning() << "Unknown event " << event << std::endl; + } + + popup->destroy(); + + return ret; +} + +YPopupInternal::StringArray YPopupInternal::editNewStringArray(const std::string &label) +{ + YPopupInternal::StringArray ret { "", "", "" }; + + if (editStringArray(ret, label)) + return ret; + else + // empty array + return StringArray(); +} \ No newline at end of file diff --git a/src/YPopupInternal.h b/src/YPopupInternal.h new file mode 100644 index 0000000..8cbc02c --- /dev/null +++ b/src/YPopupInternal.h @@ -0,0 +1,47 @@ +/* + Copyright (C) 2016 SUSE LLC + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include + +// Internal helper class for YDialogSpy and YPropertyEditor +class YPopupInternal +{ +public: + + /** + * Display a simple popup dialog with OK button + * @param label the message to display + */ + static void message(const std::string &label); + + typedef std::vector StringArray; + + /** + * Display a popup dialog with several input fields + * @param array fields to edit + * @param label title of the dialog + * @return true if dialog was closed by [OK], false otherwise + */ + static bool editStringArray(StringArray &array, const std::string &label); + + /** + * Display a popup dialog with 3 initially empty input fields + * @param label title of the dialog + * @return Entered values in a StringArray, if canceled the array is empty. + */ + static StringArray editNewStringArray(const std::string &label); +}; diff --git a/src/YProgressBar.cc b/src/YProgressBar.cc new file mode 100644 index 0000000..134ca7d --- /dev/null +++ b/src/YProgressBar.cc @@ -0,0 +1,154 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YProgressBar.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YProgressBar.h" + +struct YProgressBarPrivate +{ + YProgressBarPrivate( const std::string & label, + int maxValue ) + : label( label ) + , maxValue( maxValue ) + , value( 0 ) + { + if ( maxValue < 1 ) + maxValue = 1; + } + + std::string label; + int maxValue; + int value; +}; + + + + +YProgressBar::YProgressBar( YWidget * parent, + const std::string & label, + int maxValue ) + : YWidget( parent ) + , priv( new YProgressBarPrivate( label, maxValue ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setStretchable( YD_VERT, false ); +} + + +YProgressBar::~YProgressBar() +{ + // NOP +} + + +std::string YProgressBar::label() +{ + return priv->label; +} + + +void YProgressBar::setLabel( const std::string & label ) +{ + priv->label = label; +} + + +int YProgressBar::maxValue() const +{ + return priv->maxValue; +} + + +int YProgressBar::value() const +{ + return priv->value; +} + + +void YProgressBar::setValue( int newValue ) +{ + if ( newValue < 0 ) + newValue = 0; + + if ( newValue > priv->maxValue ) + newValue = priv->maxValue; + + priv->value = newValue; +} + + +const YPropertySet & +YProgressBar::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property integer Value the current progress + * @property std::string Label caption above the progress bar + */ + propSet.add( YProperty( YUIProperty_Value, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YProgressBar::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.integerVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YProgressBar::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YProgressBar.h b/src/YProgressBar.h new file mode 100644 index 0000000..718352f --- /dev/null +++ b/src/YProgressBar.h @@ -0,0 +1,126 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YProgressBar.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YProgressBar_h +#define YProgressBar_h + +#include "YWidget.h" + +class YProgressBarPrivate; + + +/** + * A progress bar, showing completion of value() out of maxValue() parts. + **/ +class YProgressBar : public YWidget +{ +protected: + /** + * Constructor. + **/ + YProgressBar( YWidget * parent, + const std::string & label, + int maxValue = 100 ); + +public: + /** + * Destructor. + **/ + virtual ~YProgressBar(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YProgressBar"; } + + /** + * Get the label (the caption above the progress bar). + **/ + std::string label(); + + /** + * Set the label (the caption above the progress bar). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Return the maximum progress value. + * Notice that this value can only be set in the constructor. + **/ + int maxValue() const; + + /** + * Return the current progress value. + **/ + int value() const; + + /** + * Set the current progress value ( <= maxValue() ). + * + * Derived classes should reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setValue( int newValue ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + +private: + + ImplPtr priv; +}; + + +#endif // YProgressBar_h diff --git a/src/YProperty.cc b/src/YProperty.cc new file mode 100644 index 0000000..24a9048 --- /dev/null +++ b/src/YProperty.cc @@ -0,0 +1,173 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YProperty.cc + + Author: Stefan Hundhammer + +/-*/ + +#include "YProperty.h" +#include "YUIException.h" + + + +std::string +YProperty::typeAsStr( YPropertyType type ) +{ + switch ( type ) + { + case YUnknownPropertyType: return ""; + case YOtherProperty: return ""; + case YStringProperty: return "String"; + case YBoolProperty: return "Bool"; + case YIntegerProperty: return "Integer"; + + // Intentionally omitting default branch + // so the compiler catches unhandled enum values + } + + return ""; +} + + +YPropertyValue::~YPropertyValue() +{ +} + +bool YPropertyValue::operator==( const YPropertyValue &other ) const +{ + // compare the type first + if (_type != other.type()) return false; + + // then compare the values + switch ( _type ) + { + case YStringProperty: return _stringVal == other.stringVal(); + case YBoolProperty: return _boolVal == other.boolVal(); + case YIntegerProperty: return _integerVal == other.integerVal(); + + case YUnknownPropertyType: + case YOtherProperty: + YUI_THROW( YUIException( "Cannot compare " + typeAsStr() + " properties") ); + } + + // mark this part as unreachable to avoid "end of non-void function" error, + // YUI_THROW is a macro for a function template and cannot be marked as "noreturn" + __builtin_unreachable(); +} + +bool YPropertyValue::operator!=( const YPropertyValue &other ) const +{ + return !(*this == other); +} + +YPropertySet::YPropertySet() +{ + // NOP +} + + +void +YPropertySet::check( const std::string & propertyName ) const +{ + if ( ! contains( propertyName ) ) + YUI_THROW( YUIUnknownPropertyException( propertyName ) ); +} + + +void +YPropertySet::check( const std::string & propertyName, YPropertyType type ) const +{ + if ( ! contains( propertyName, type ) ) + YUI_THROW( YUIUnknownPropertyException( propertyName ) ); + + // YPropertySet::contains( const std::string &, YPropertyType ) will throw + // a YUIPropertyTypeMismatchException, if applicable +} + + +bool +YPropertySet::contains( const std::string & propertyName ) const throw() +{ + for ( YPropertySet::const_iterator it = _properties.begin(); + it != _properties.end(); + ++it ) + { + if ( it->name() == propertyName ) + return true; + } + + return false; +} + + +bool +YPropertySet::contains( const std::string & propertyName, YPropertyType type ) const +{ + for ( YPropertySet::const_iterator it = _properties.begin(); + it != _properties.end(); + ++it ) + { + if ( it->name() == propertyName ) + { + if ( it->isReadOnly() ) + YUI_THROW( YUISetReadOnlyPropertyException( *it ) ); + + if ( it->type() == type || + it->type() == YOtherProperty ) // "Other" could be anything + return true; + + YUI_THROW( YUIPropertyTypeMismatchException( *it, type ) ); + } + } + + return false; +} + + +void +YPropertySet::add( const YProperty & prop ) +{ + _properties.push_back( prop ); +} + + +void +YPropertySet::add( const YPropertySet & otherSet ) +{ + for ( YPropertySet::const_iterator it = otherSet.propertiesBegin(); + it != otherSet.propertiesEnd(); + ++it ) + { + add( *it ); + } +} + + +YPropertySet::const_iterator +YPropertySet::propertiesBegin() const +{ + return _properties.begin(); +} + +YPropertySet::const_iterator +YPropertySet::propertiesEnd() const +{ + return _properties.end(); +} diff --git a/src/YProperty.h b/src/YProperty.h new file mode 100644 index 0000000..0bba5fd --- /dev/null +++ b/src/YProperty.h @@ -0,0 +1,307 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YProperty.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YProperty_h +#define YProperty_h + +#include +#include + + + +enum YPropertyType +{ + YUnknownPropertyType = 0, + YOtherProperty, // requires futher checking + YStringProperty, // const std::string & + YBoolProperty, // bool + YIntegerProperty // YCP Integer == C++ long long +}; + +class YWidget; +class YProperty; + +typedef long long YInteger; + + +/** + * Class for widget properties. + **/ +class YProperty +{ +public: + /** + * Constructor: Create a property with the specified name and type. + * 'isReadOnly' is for properties that cannot be set, only retrieved. + **/ + YProperty( const std::string & name, YPropertyType type, bool isReadOnly = false ) + : _name( name ) + , _type( type ) + , _isReadOnly( isReadOnly ) + {} + + /** + * Returns the name of this property. + **/ + std::string name() const { return _name; } + + /** + * Returns the type of this property. + **/ + YPropertyType type() const { return _type; } + + /** + * Returns 'true' if this property cannot be changed, only retrieved. + **/ + bool isReadOnly() const { return _isReadOnly; } + + /** + * Returns the type of this property as string. + **/ + std::string typeAsStr() const { return YProperty::typeAsStr( _type ); } + + /** + * Returns a string description of a property type. + **/ + static std::string typeAsStr( YPropertyType type ); + +private: + + std::string _name; + YPropertyType _type; + bool _isReadOnly; +}; + + +/** + * Transport class for the value of simple properties. + * + * More complex properties (lists of items, tree descriptions, ...) have to + * be handled specifically someplace else, but most properties are of + * simple types and can be treated in similar ways. + **/ +class YPropertyValue +{ +public: + + /** + * Constructor for string properties. + **/ + YPropertyValue( const std::string & str ): + _type( YStringProperty ), _stringVal( str ) {} + + /** + * Constructor for const char * (string) properties. + **/ + YPropertyValue( const char * str ): + _type( YStringProperty ), _stringVal( str ) {} + + /** + * Constructor for bool properties. + **/ + explicit YPropertyValue( bool b ): + _type( YBoolProperty ), _boolVal( b ) {} + + /** + * Constructor for numerical (YCP integer) properties. + **/ + explicit YPropertyValue( YInteger num ): + _type( YIntegerProperty ), _integerVal( num ) {} + + /** + * Constructor for numerical (YCP integer) properties. + **/ + explicit YPropertyValue( int num ): + _type( YIntegerProperty ), _integerVal( num ) {} + + explicit YPropertyValue( YPropertyType type ) : + _type( type ) {} + + /** + * Default constructor + **/ + YPropertyValue(): + _type( YUnknownPropertyType ) {} + + /** + * Destructor. + **/ + ~YPropertyValue(); + + /** + * Equality operator, can compare with another YPropertyValue. + * @throw YUIException for incompatible property types + * @return true if the value is the same + */ + bool operator==( const YPropertyValue &other ) const; + + /** Inequality operator + * @throw YUIException for incompatible property types + * @see operator== + */ + bool operator!=( const YPropertyValue &other ) const; + + /** + * Returns the type of this property value. + * Use this to determine which xyVal() method to use. + **/ + YPropertyType type() const { return _type; } + + /** + * Returns the type of this property value as string. + **/ + std::string typeAsStr() const { return YProperty::typeAsStr( _type ); } + + /** + * Methods to get the value of this property. + * Check with type() which one to use. + **/ + std::string stringVal() const { return _stringVal; } + bool boolVal() const { return _boolVal; } + YInteger integerVal() const { return _integerVal; } + + +private: + + YPropertyType _type; + std::string _stringVal; + bool _boolVal; + YInteger _integerVal; +}; + + +/** + * A set of properties to check names and types against. + **/ +class YPropertySet +{ +public: + /** + * Constructor. + **/ + YPropertySet(); + + /** + * Check if a property 'propertyName' exists in this property set. + * Throw a YUIUnknownPropertyException if it does not exist. + * Use YPropertySet::contains() for a check that simply returns 'false' + * if it does not exist. + **/ + void check( const std::string & propertyName ) const; + + /** + * Check if a property 'propertyName' exists in this property set. + * Throw a YUIUnknownPropertyException if it does not exist. + * + * If there is a property with that name, check also the expected type + * against 'type'. If the types don't match, throw a + * YUIPropertyTypeMismatchException. + * If the property is read-only, throw a YUISetReadOnlyPropertyException. + **/ + void check( const std::string & propertyName, YPropertyType type ) const; + + /** + * Same as above, overloaded for convenience. + **/ + void check( const YProperty & prop ) const + { check( prop.name(), prop.type() ); } + + /** + * Check if a property 'propertyName' exists in this property set. + * Returns 'true' if it exists, 'false' if not. + * + * Use YPropertySet::check() for a check that throws exceptions if + * there is no such property. + **/ + bool contains( const std::string & propertyName ) const throw(); + + /** + * Check if a property 'propertyName' exists in this property set. + * Returns 'true' if it exists, 'false' if not. + * + * If there is a property with that name, check also the expected type + * against 'type'. If the types don't match, throw a + * YUIPropertyTypeMismatchException. + * + * If the property is read-only, throw a YUISetReadOnlyPropertyException. + * + * Use YPropertySet::check() for a check that throws exceptions if + * there is no such property. + **/ + bool contains( const std::string & propertyName, YPropertyType type ) const; + + /** + * Same as above, overloaded for convenience. + **/ + bool contains( const YProperty & prop ) const + { return contains( prop.name(), prop.type() ); } + + /** + * Returns 'true' if this property set does not contain anything. + **/ + bool isEmpty() const { return _properties.empty(); } + + /** + * Returns the number of properties in this set. + **/ + int size() const { return (int) _properties.size(); } + + /** + * Add a property to this property set. + **/ + void add( const YProperty & prop ); + + /** + * Adds all properties of another property set. + * + * If that other set contains duplicates (properties that are already + * in this set), those others will never be found with lookup(). + **/ + void add( const YPropertySet & otherSet ); + + typedef std::vector::const_iterator const_iterator; + + /** + * Returns an iterator that points to the first property in this set. + **/ + const_iterator propertiesBegin() const; + + /** + * Returns an iterator that points after the last property in this set. + **/ + const_iterator propertiesEnd() const; + +private: + + /** + * This class uses a simple std::vector as a container to hold the + * properties: Normally, the number of properties for each widget is so + * small (2..5) that using any more sophisticated container like + * std::set etc. would not pay off. More likely, it would add overhead. + **/ + std::vector _properties; +}; + + +#endif // YProperty_h diff --git a/src/YPropertyEditor.cc b/src/YPropertyEditor.cc new file mode 100644 index 0000000..ab4fcce --- /dev/null +++ b/src/YPropertyEditor.cc @@ -0,0 +1,296 @@ +/* + Copyright (C) 2016 SUSE LLC + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define YUILogComponent "ui-property-editor" +#include "YUILog.h" + +class YPropertyEditorPriv +{ +public: + + YPropertyEditorPriv(YWidget * widget) : _widget(widget), + popup(nullptr), combo(nullptr), intfield(nullptr), + input(nullptr), okButton(nullptr), cancelButton(nullptr) + {} + + bool edit(const std::string &property); + +private: + + /** + * show the dialog on the screen + * @param property Name of the property to edit + */ + void show(const std::string &property); + + /** + * Run the main event loop + * @param property Name of the property to edit + * @return true if the value has been changed, false otherwise + */ + bool run(const std::string &property); + + /** + * Close the dialog window + */ + void close(); + + /** + * Refresh the dialog conatining the widget + */ + void refreshDialog(); + + YWidget * _widget; + + /** + * Is the property read-only? + * @param property Name of the property + * @return true if it is read-only, false if it can be changed + */ + bool isReadOnly(const std::string &property); + + // UI widgets + // the main popup + YDialog *popup; + + // input widgets + YComboBox *combo; + YIntField *intfield; + YInputField *input; + + // buttons + YPushButton *okButton; + YPushButton *cancelButton; + + /** + * Is the property editable? Editable property is not read-only and + * it is String, Integer or Boolean type. + * @param property Name of the property + * @return true if the property can be changed + */ + bool editable(const std::string &property); +}; + +/** + * Helper method - refresh the dialog containing the widget + * @param widget [description] + */ +void YPropertyEditorPriv::refreshDialog() +{ + auto dialog = _widget->findDialog(); + if (dialog) dialog->recalcLayout(); +} + +bool YPropertyEditorPriv::edit(const std::string &property) +{ + if (!_widget || !editable(property)) return false; + + yuiMilestone() << "editing property \"" << property << "\" (type: " << + _widget->getProperty(property).typeAsStr() << ")"; + + show(property); + bool changed = run(property); + close(); + + return changed; +} + +bool YPropertyEditorPriv::isReadOnly(const std::string &property) +{ + // is the property read-only? + YPropertySet propSet = _widget->propertySet(); + for ( YPropertySet::const_iterator it = propSet.propertiesBegin(); + it != propSet.propertiesEnd(); + ++it ) + { + YProperty prop = *it; + + if (prop.name() == property) + { + return prop.isReadOnly(); + } + } + + // we cannot edit an unknown property, throw an exception + YUI_THROW( YUIException( "Unknown property: " + property) ); + + // FIXME: never reached, just make the compiler happy (can it be improved?) + return false; +} + +void YPropertyEditorPriv::show(const std::string &property) +{ + YPropertyValue prop_value = _widget->getProperty(property); + YPropertyType type = prop_value.type(); + + auto f = YUI::widgetFactory(); + + popup = f->createPopupDialog(); + auto vbox = f->createVBox(popup); + + if (type == YBoolProperty) + { + combo = f->createComboBox(vbox, property); + combo->setNotify(true); + + YItemCollection items; + items.push_back(new YItem("true")); + items.push_back(new YItem("false")); + combo->addItems(items); + combo->setValue(prop_value.boolVal() ? "true" : "false"); + } + else if (type == YIntegerProperty) + { + intfield = f->createIntField(vbox, property, + // we do not know anything about that property so use the + // max int and min int values here + std::numeric_limits::min(), std::numeric_limits::max(), + prop_value.integerVal()); + intfield->setNotify(true); + } + else if (type == YStringProperty) + { + input = f->createInputField(vbox, property); + input->setNotify(true); + input->setValue(prop_value.stringVal()); + } + + auto bbox = f->createButtonBox(vbox); + okButton = f->createPushButton(bbox, "OK"); + okButton->setRole(YOKButton); + okButton->setDefaultButton(); + cancelButton = f->createPushButton(bbox, "Cancel"); + cancelButton->setRole(YCancelButton); +} + +void YPropertyEditorPriv::close() +{ + popup->destroy(); + + // nullify the widget pointers, just to be sure... + popup = NULL; + okButton = NULL; + cancelButton = NULL; + combo = NULL; + intfield = NULL; + input = NULL; +} + +bool YPropertyEditorPriv::run(const std::string &property) +{ + // backup the original property value so it can be restored after + // clicking the [Cancel] button later + YPropertyValue orig = _widget->getProperty(property);; + + while (true) + { + YEvent * event = popup->waitForEvent(); + if (event) + { + if (event->widget() == cancelButton || event->eventType() == YEvent::CancelEvent) + { + // restore the original value + if (_widget->getProperty(property) != orig) + { + _widget->setProperty(property, orig); + refreshDialog(); + } + + // not modified + return false; + } + else if (event->widget() == okButton) + { + return _widget->getProperty(property) != orig; + } + else if (event->widget() == combo) + { + std::string value = combo->value(); + yuiMilestone() << "Value changed to " << value; + _widget->setProperty(property, YPropertyValue(value == "true")); + refreshDialog(); + } + else if (event->widget() == input) + { + std::string value = input->value(); + yuiMilestone() << "Value changed to " << value; + + _widget->setProperty(property, YPropertyValue(value)); + refreshDialog(); + } + else if (event->widget() == intfield) + { + int value = intfield->value(); + yuiMilestone() << "Value changed to " << value; + + _widget->setProperty(property, YPropertyValue(value)); + refreshDialog(); + } + } + } +} + +bool YPropertyEditorPriv::editable(const std::string &property) +{ + YPropertyValue prop_value = _widget->getProperty(property); + + // is the property read-only? + if (isReadOnly(property)) + { + YPopupInternal::message("Property \"" + property + "\" is read only!"); + return false; + } + + YPropertyType type = prop_value.type(); + // edit special properties cannot be edited + if (type != YBoolProperty && type != YStringProperty && type != YIntegerProperty) + { + return false; + } + + return true; +} + +bool YPropertyEditor::edit(const std::string &property) +{ + return priv->edit(property); +} + +YPropertyEditor::YPropertyEditor(YWidget * widget) +: priv(new YPropertyEditorPriv(widget)) +{ +} + +YPropertyEditor::~YPropertyEditor() +{ +} diff --git a/src/YPropertyEditor.h b/src/YPropertyEditor.h new file mode 100644 index 0000000..764c401 --- /dev/null +++ b/src/YPropertyEditor.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2016 SUSE LLC + + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef YPropertyEditor_h +#define YPropertyEditor_h + +#include + +#include "ImplPtr.h" + +class YWidget; +class YPropertyEditorPriv; + +/** + * An internal helper class for displaying the widget property editor + * in the spy dialog. + * @see YDialogSpy + */ +class YPropertyEditor +{ +public: + /** + * Constructor + * @param widget the target widget + */ + YPropertyEditor(YWidget * widget); + + virtual ~YPropertyEditor(); + + /** + * Display a popup for editing a widget property. + * @param property name of the property to edit + * @return true if the property has been changed, false otherwise + */ + bool edit(const std::string &property); + +private: + + ImplPtr priv; +}; + +#endif diff --git a/src/YPushButton.cc b/src/YPushButton.cc new file mode 100644 index 0000000..26bb591 --- /dev/null +++ b/src/YPushButton.cc @@ -0,0 +1,274 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YPushButton.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUI.h" +#include "YApplication.h" +#include "YDialog.h" +#include "YUISymbols.h" +#include "YPushButton.h" + +using std::endl; + + +struct YPushButtonPrivate +{ + YPushButtonPrivate( const std::string & label ) + : label( label ) + , isDefaultButton( false ) + , setDefaultButtonRecursive( false ) + , isHelpButton( false ) + , isRelNotesButton( false ) + , role( YCustomButton ) + {} + + std::string label; + bool isDefaultButton; + bool setDefaultButtonRecursive; + bool isHelpButton; + bool isRelNotesButton; + YButtonRole role; +}; + + +YPushButton::YPushButton( YWidget * parent, const std::string & label ) + : YWidget( parent ) + , priv( new YPushButtonPrivate( label ) ) +{ + int fkey = YUI::app()->defaultFunctionKey( label ); + + if ( fkey > 0 && ! hasFunctionKey() ) + setFunctionKey( fkey ); +} + + +YPushButton::~YPushButton() +{ + YDialog * dialog = findDialog(); + + if ( dialog && dialog->defaultButton() == this ) + { + dialog->setDefaultButton( 0 ); + } +} + + +void YPushButton::setLabel( const std::string & label ) +{ + priv->label = label; +} + + +std::string YPushButton::label() const +{ + return priv->label; +} + + +bool YPushButton::isDefaultButton() const +{ + return priv->isDefaultButton; +} + + +void YPushButton::setDefaultButton( bool isDefaultButton ) +{ + priv->isDefaultButton = isDefaultButton; + + if ( ! priv->setDefaultButtonRecursive ) + { + // Prevent endless recursion if dialog->setDefaultButton() + // calls this function again + + priv->setDefaultButtonRecursive = true; + + YDialog * dialog = findDialog(); + + if ( dialog ) + { + if ( isDefaultButton ) + dialog->setDefaultButton( this ); + else + { + if ( dialog->defaultButton() == this ) + dialog->setDefaultButton( 0 ); + } + } + + priv->setDefaultButtonRecursive = false; + } +} + + +bool YPushButton::isHelpButton() const +{ + return priv->isHelpButton; +} + + +void YPushButton::setHelpButton( bool helpButton ) +{ + priv->isHelpButton = helpButton; + priv->role = YHelpButton; +} + +bool YPushButton::isRelNotesButton() const +{ + return priv->isRelNotesButton; +} + + +void YPushButton::setRelNotesButton( bool relNotesButton ) +{ + priv->isRelNotesButton = relNotesButton; + priv->role = YRelNotesButton; +} + +/* setRole can try to guess function key, but only if there isn't a selected + function key already +*/ +void YPushButton::setRole( YButtonRole role ) +{ + priv->role = role; + int old_function_key = functionKey(); + if (!hasFunctionKey()) // otherwise function key was already determined + { + switch (priv->role) + { + case YOKButton: YWidget::setFunctionKey( 10 ); break; + case YCancelButton: YWidget::setFunctionKey( 9 ); break; + case YApplyButton: YWidget::setFunctionKey( 10 ); break; + case YHelpButton: YWidget::setFunctionKey( 1 ); break; + default: break; + } + if ( functionKey() != old_function_key ) + { + yuiMilestone() << "Guessing function key F" << functionKey() + << " for " << this + << " from button role " << priv->role + << endl; + } + } +} + +YButtonRole YPushButton::role() const +{ + return priv->role; +} + +/* setFunctionKey (besides setting the function key) should try to guess button + role, but only if button role is not yet determined. +*/ +void YPushButton::setFunctionKey( int fkey_no ) +{ + YWidget::setFunctionKey( fkey_no ); + YButtonRole oldRole = priv->role; + + if (priv->role == YCustomButton) // otherwise role was already determined + { + switch ( functionKey() ) // base class method might have changed it + { + case 10: priv->role = YOKButton; break; + case 9: priv->role = YCancelButton; break; + case 1: priv->role = YHelpButton; break; + default: break; + } + if ( priv->role != oldRole ) + { + yuiMilestone() << "Guessing button role " << priv->role + << " for " << this + << " from function key F" << functionKey() + << endl; + } + } +} + + +const YPropertySet & +YPushButton::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Label text on the button + */ + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YPushButton::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special handling necessary +} + + +YPropertyValue +YPushButton::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} + + +std::ostream & operator<<( std::ostream & stream, YButtonRole role ) +{ + switch ( role ) + { + case YCustomButton: stream << "YCustomButton"; break; + case YOKButton: stream << "YOKButton"; break; + case YApplyButton: stream << "YApplyButton"; break; + case YCancelButton: stream << "YCancelButton"; break; + case YHelpButton: stream << "YHelpButton"; break; + case YRelNotesButton: stream << "YRelNotesButton"; break; + + default: + stream << ""; + break; + } + + return stream; +} diff --git a/src/YPushButton.h b/src/YPushButton.h new file mode 100644 index 0000000..5b65c98 --- /dev/null +++ b/src/YPushButton.h @@ -0,0 +1,231 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YPushButton.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YPushButton_h +#define YPushButton_h + +#include "YWidget.h" + +class YPushButtonPrivate; + + + +/** + * A push button; may have an icon, and a F-key shortcut. + **/ +class YPushButton : public YWidget +{ +protected: + /** + * Constructor. + **/ + YPushButton( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YPushButton(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YPushButton"; } + + /** + * Get the label (the text on the button). + **/ + std::string label() const; + + /** + * Set the label (the text on the button). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Set this button's icon from an icon file in the UI's default icon + * directory. Clear the icon if the name is empty. + * + * This default implementation does nothing. + * UIs that can handle icons can choose to overwrite this method. + **/ + virtual void setIcon( const std::string & iconName ) {} + + /** + * Returns 'true' if this is the dialog's default button, i.e. the one + * button that gets activated if the user hits the [Return] key anywhere in + * the dialog. + **/ + bool isDefaultButton() const; + + /** + * Make this button the default button. + * + * Derived classes should reimplement this, but call this base class + * function in the overwritten function. + **/ + virtual void setDefaultButton( bool def = true ); + + /** + * Set a predefined role for this button. + * + * This is important when the button is a child of a YButtonBox so the + * layout can be arranged according to the conventions of the current UI or + * desktop environment. + * + * See YButtonBox.h for more details. YButtonRole is defined in YTypes.h + * + * The default is YCustomButton, i.e., no predefined role. + * setFunctionKey() uses some heuristics to map function keys to buttons: + * + * F10 -> YOkButton + * F9 -> YCancelButton + * F1 -> YHelpButton + * + * Derived classes are free to reimplement this, but they should call this + * base class function in the overwritten function. + **/ + virtual void setRole( YButtonRole role ); + + /** + * Return the role of this button. + **/ + YButtonRole role() const; + + /** + * Assign a function key to this widget + * (1 for F1, 2 for F2, etc.; 0 for none) + * + * Reimplemented from YWidget to map function keys to button roles. + * + * Derived classes may want to overwrite this function, but they should + * call this base class function in the new function. + **/ + virtual void setFunctionKey( int fkey_no ); + + + /** + * Returns 'true' if this is a "Help" button. + * + * When activated, a help button will traverse up its widget hierarchy and + * search for the topmost widget with a helpText() set and display that + * help text in a pop-up dialog (with a local event loop). + * + * NOTE that this is only done during YDialog::waitForEvent() (i.e. in YCP + * UI::WaitForEvent(), UI::UserInput(), UI::TimeoutUserInput() ) and not + * during YDialog::pollEvent() (i.e. YCP UI::PollInput()) since displaying + * the help text will block the application until the user closes the help + * text. + **/ + bool isHelpButton() const; + + /** + * Make this button a help button. + * + * Derived classes are free to reimplement this, but they should call this + * base class method in the overloaded function. + **/ + virtual void setHelpButton( bool helpButton = true ); + + /** + * Returns 'true' if this is a "Release Notes" button. + * + * NOTE that this is only done during YDialog::waitForEvent() (i.e. in YCP + * UI::WaitForEvent(), UI::UserInput(), UI::TimeoutUserInput() ) and not + * during YDialog::pollEvent() (i.e. YCP UI::PollInput()) since displaying + * the release notes will block the application until the user closes the + * text. + **/ + bool isRelNotesButton() const; + + /** + * Make this button a release notes button. + * + * Derived classes are free to reimplement this, but they should call this + * base class method in the overloaded function. + **/ + virtual void setRelNotesButton( bool relNotesButton = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + +private: + + ImplPtr priv; +}; + + +std::ostream & operator<<( std::ostream & stream, YButtonRole role ); + + +typedef YPushButton YIconButton; + + +#endif // YPushButton_h diff --git a/src/YRadioButton.cc b/src/YRadioButton.cc new file mode 100644 index 0000000..0753f64 --- /dev/null +++ b/src/YRadioButton.cc @@ -0,0 +1,205 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRadioButton.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YUIException.h" +#include "YMacroRecorder.h" +#include "YRadioButtonGroup.h" +#include "YRadioButton.h" + + + +struct YRadioButtonPrivate +{ + /** + * Constructor + **/ + YRadioButtonPrivate( const std::string & label ) + : label( label ) + , radioButtonGroup( 0 ) + , useBoldFont( false ) + {} + + // + // Data members + // + + std::string label; + YRadioButtonGroup * radioButtonGroup; + bool useBoldFont; +}; + + +YRadioButton::YRadioButton( YWidget * parent, + const std::string & label ) + : YWidget( parent ) + , priv( new YRadioButtonPrivate( label ) ) +{ + YUI_CHECK_NEW( priv ); + + // Intentionally not calling + // buttonGroup()->addRadioButton( this ); + // here because virtual functions can't be used yet (while the constructor + // isn't finished yet), and the RadioButtonGroup for sure would try to call + // YRadioButton::value() which is (pure) virtual, thus not available yet. + // + // The caller has to take care of this. +} + + +YRadioButton::~YRadioButton() +{ + if ( priv->radioButtonGroup ) + { + if ( ! priv->radioButtonGroup->beingDestroyed() ) + priv->radioButtonGroup->removeRadioButton( this ); + } +} + + +void YRadioButton::setLabel( const std::string & newLabel ) +{ + priv->label = newLabel; +} + + +std::string YRadioButton::label() const +{ + return priv->label; +} + + +bool YRadioButton::useBoldFont() const +{ + return priv->useBoldFont; +} + + +void YRadioButton::setUseBoldFont( bool bold ) +{ + priv->useBoldFont = bold; +} + + +const YPropertySet & +YRadioButton::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property boolean Value the on/off state of the RadioButton + * @property std::string Label the text on the RadioButton + */ + + propSet.add( YProperty( YUIProperty_Value, YBoolProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YRadioButton::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.boolVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YRadioButton::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} + + +YRadioButtonGroup * +YRadioButton::buttonGroup() +{ + if ( ! priv->radioButtonGroup ) + { + priv->radioButtonGroup = findRadioButtonGroup(); + } + + return priv->radioButtonGroup; +} + + +YRadioButtonGroup * +YRadioButton::findRadioButtonGroup() const +{ + YWidget * widget = parent(); + + while ( widget ) + { + YRadioButtonGroup * radioButtonGroup = dynamic_cast (widget); + + if ( radioButtonGroup ) + return radioButtonGroup; + else + widget = widget->parent(); + } + + return 0; +} + + +void +YRadioButton::saveUserInput( YMacroRecorder *macroRecorder ) +{ + if ( value() ) + { + // Only record if this radio button is on. By definition one radio + // button of the radio box _must_ be on if the user did anything, so we + // don't record a lot of redundant "ChangeWidget( ..., `Value, false )" + // calls. + + macroRecorder->recordWidgetProperty( this, YUIProperty_Value ); + } +} diff --git a/src/YRadioButton.h b/src/YRadioButton.h new file mode 100644 index 0000000..9dc62de --- /dev/null +++ b/src/YRadioButton.h @@ -0,0 +1,209 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRadioButton.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YRadioButton_h +#define YRadioButton_h + +#include "YWidget.h" + +class YRadioButtonGroup; +class YRadioButtonPrivate; + + +/** + * RadioButton: Widget for one-out-of-many selection. + * + * Only one RadioButton in a RadioBox (in a RadioButtonGroup) can be set to + * "on" at the same time. Setting any RadioButton of a RadioButtonGroup to "on" + * automatically sets all others in the same RadioButtonGroup to "off". + * + * RadioButtons customarily have a distinct visual appearance from CheckBoxes: + * + * ( ) RadioButton 1 + * (*) RadioButton 2 + * ( ) RadioButton 3 + * + * [ ] CheckBox 1 + * [*] CheckBox 2 + * [*] CheckBox 3 + **/ +class YRadioButton : public YWidget +{ +protected: + /** + * Constructor. + * + * Creates a new RadioButton with user-visible text 'label'. + * 'label' can and should contain a keyboard shortcut (designated with + * '&'). + * + * The caller has to take care to add this RadioButton to its + * RadioButtonGroup: + * + * if ( radioButton->buttonGroup() ) + * radioButton->buttonGroup()->addRadioButton( radioButton ); + * + * This can't be done in the constructor because it would involve calling a + * virtual function, which doesn't work yet within the constructor. + **/ + YRadioButton( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor: Removes the button from the radio button group. + **/ + virtual ~YRadioButton(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + * + * Reimplemented from YWidget. + **/ + virtual const char * widgetClass() const { return "YRadioButton"; } + + /** + * Get the current on/off value: + * 'true' if checked, 'false' if unchecked. + * + * Derived classes are required to implement this. + **/ + virtual bool value() = 0; + + /** + * Set the radio button value (on/off). + * + * Derived classes are required to implement this. + **/ + virtual void setValue( bool checked ) = 0; + + /** + * Get the label (the text on the RadioButton). + **/ + std::string label() const; + + /** + * Set the label (the text on the RadioButton). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Returns 'true' if a bold font should be used. + **/ + bool useBoldFont() const; + + /** + * Indicate whether or not a bold font should be used. + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setUseBoldFont( bool bold = true ); + + /** + * Get a pointer to the radio button group this button belongs to. + **/ + YRadioButtonGroup * buttonGroup(); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property set upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + +protected: + /** + * Traverse the widget hierarchy upwards to find the corresponding + * YRadioButtonGroup, i.e. the class that controls the radio box behaviour + * (i.e. that makes sure that no more than one RadioButton is set to "on" + * at the same time). + **/ + YRadioButtonGroup * findRadioButtonGroup() const; + + /** + * Save the widget's user input to a macro recorder. + * + * Reimplemented from YWidget because only radio buttons that are on (no + * more than one per radio box) are recorded. + **/ + virtual void saveUserInput( YMacroRecorder *macroRecorder ); + +private: + + ImplPtr priv; +}; + + +#endif // YRadioButton_h diff --git a/src/YRadioButtonGroup.cc b/src/YRadioButtonGroup.cc new file mode 100644 index 0000000..0256a4e --- /dev/null +++ b/src/YRadioButtonGroup.cc @@ -0,0 +1,169 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRadioButtonGroup.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YRadioButton.h" +#include "YRadioButtonGroup.h" + + +struct YRadioButtonGroupPrivate +{ + YRadioButtonGroupPrivate() + {} + + + YRadioButtonList buttonList; +}; + + + + +YRadioButtonGroup::YRadioButtonGroup( YWidget * parent ) + : YSingleChildContainerWidget( parent ) + , priv( new YRadioButtonGroupPrivate() ) +{ + YUI_CHECK_NEW( priv ); +} + + +YRadioButtonGroup::~YRadioButtonGroup() +{ +} + + +YRadioButtonListConstIterator +YRadioButtonGroup::radioButtonsBegin() const +{ + return priv->buttonList.begin(); +} + + +YRadioButtonListConstIterator +YRadioButtonGroup::radioButtonsEnd() const +{ + return priv->buttonList.end(); +} + + +int +YRadioButtonGroup::radioButtonsCount() const +{ + return priv->buttonList.size(); +} + + +void +YRadioButtonGroup::addRadioButton( YRadioButton * button ) +{ + priv->buttonList.push_back( button ); +} + + +void +YRadioButtonGroup::removeRadioButton( YRadioButton * button ) +{ + priv->buttonList.remove( button ); +} + + +void +YRadioButtonGroup::uncheckOtherButtons( YRadioButton * selectedRadioButton ) +{ + for ( YRadioButtonListConstIterator it = radioButtonsBegin(); + it != radioButtonsEnd(); + ++it ) + { + if ( *it != selectedRadioButton ) + (*it)->setValue( false ); + } +} + + +YRadioButton * +YRadioButtonGroup::currentButton() const +{ + for ( YRadioButtonListConstIterator it = radioButtonsBegin(); + it != radioButtonsEnd(); + ++it ) + { + if ( (*it)->value() ) + return *it; + } + + return 0; +} + + +const YPropertySet & +YRadioButtonGroup::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property any CurrentButton widget ID of the currently selected RadioButton of this group + * @property any Value Alias for CurrentButton + */ + propSet.add( YProperty( YUIProperty_Value, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentButton, YOtherProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YRadioButtonGroup::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_CurrentButton || + propertyName == YUIProperty_Value ) return false; // Needs special handling + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YRadioButtonGroup::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_CurrentButton || + propertyName == YUIProperty_Value ) return YPropertyValue( YOtherProperty ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YRadioButtonGroup.h b/src/YRadioButtonGroup.h new file mode 100644 index 0000000..063a52e --- /dev/null +++ b/src/YRadioButtonGroup.h @@ -0,0 +1,160 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRadioButtonGroup.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YRadioButtonGroup_h +#define YRadioButtonGroup_h + +#include "YSingleChildContainerWidget.h" + +class YRadioButton; +class YRadioButtonGroupPrivate; + +typedef std::list YRadioButtonList; +typedef YRadioButtonList::iterator YRadioButtonListIterator; +typedef YRadioButtonList::const_iterator YRadioButtonListConstIterator; + + +/** + * A group of YRadioButton widgets. + **/ +class YRadioButtonGroup : public YSingleChildContainerWidget +{ +protected: + /** + * Constructor. + **/ + YRadioButtonGroup( YWidget * parent ); + +public: + /** + * Destructor. + **/ + virtual ~YRadioButtonGroup(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YRadioButtonGroup"; } + + /** + * Find the currently selected button. + **/ + YRadioButton * currentButton() const; + + /** + * The same as currentButton() above for convenience. + **/ + YRadioButton * value() const { return currentButton(); } + + /** + * Add a RadioButton to this button group. RadioButtons are required to + * call this in their constructor. + * + * Derived classes are free to overload this, but they should call this + * base class function in the overloaded function. + **/ + virtual void addRadioButton( YRadioButton * radioButton ); + + /** + * Remove a RadioButton from this button group. RadioButtons are required + * to call this in their destructor, but only if the button group is not + * also in the process of being destroyed (otherwise there may be race + * conditions with child widgets already destroyed): + * + * if ( ! buttonGroup()->beingDestroyed ) + * buttonGroup()->removeRadioButton( this ); + **/ + virtual void removeRadioButton( YRadioButton * radioButton ); + + /** + * Unchecks all radio buttons except one. This method + * can be used by a concrete UI (the Qt UI or the NCurses UI) + * in the implementation of YRadioButton::setValue(). + **/ + void uncheckOtherButtons( YRadioButton * radioButton ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property set upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + +protected: + + /** + * Return an iterator that points to the first RadioButton of this button + * group. + * + * Note that RadioButtons in this group may be direct or indirect children + * of the group, so don't confuse this with YWidget::widgetsBegin(). + **/ + YRadioButtonListConstIterator radioButtonsBegin() const; + + /** + * Return an iterator that points behind the last RadioButton of this + * button group. + **/ + YRadioButtonListConstIterator radioButtonsEnd() const; + + /** + * Return the number of RadioButtons in this button group. + **/ + int radioButtonsCount() const; + + +private: + + ImplPtr priv; +}; + + +#endif // YRadioButtonGroup_h diff --git a/src/YReplacePoint.cc b/src/YReplacePoint.cc new file mode 100644 index 0000000..ffdb525 --- /dev/null +++ b/src/YReplacePoint.cc @@ -0,0 +1,38 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YReplacePoint.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YReplacePoint.h" + +YReplacePoint::YReplacePoint( YWidget * parent ) + : YSingleChildContainerWidget( parent ) +{ + // NOP +} + + +void YReplacePoint::showChild() +{ + // NOP +} diff --git a/src/YReplacePoint.h b/src/YReplacePoint.h new file mode 100644 index 0000000..32f90f4 --- /dev/null +++ b/src/YReplacePoint.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YReplacePoint.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YReplacePoint_h +#define YReplacePoint_h + +#include "YSingleChildContainerWidget.h" + +/** + * A placeholder that can have its contents exchanged, using ReplaceWidget. + **/ +class YReplacePoint : public YSingleChildContainerWidget +{ +protected: + /** + * Constructor + **/ + YReplacePoint( YWidget * parent ); + +public: + /** + * Show a newly added child. The application using the ReplacePoint is + * required to call this after the new child is created. + * + * This cannot be done in the child widget's constructor (e.g., by + * overwriting YWidget::addChild()) since at that point + * YWidget::widgetRep() may or may not be initialized yet. + * + * This default implementation does nothing. Derived classes should + * reimplement this to make new child widgets visible. + **/ + virtual void showChild(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YReplacePoint"; } +}; + + +#endif // YReplacePoint_h diff --git a/src/YRichText.cc b/src/YRichText.cc new file mode 100644 index 0000000..60e3c8e --- /dev/null +++ b/src/YRichText.cc @@ -0,0 +1,166 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRichText.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YRichText.h" + + +struct YRichTextPrivate +{ + /** + * Constructor. + **/ + YRichTextPrivate( const std::string & text, bool plainTextMode ) + : text( text ) + , plainTextMode( plainTextMode ) + , autoScrollDown ( false ) + , shrinkable( false ) + {} + + std::string text; + bool plainTextMode; + bool autoScrollDown; + bool shrinkable; +}; + + + + +YRichText::YRichText( YWidget * parent, const std::string & text, bool plainTextMode ) + : YWidget( parent ) + , priv( new YRichTextPrivate( text, plainTextMode ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YRichText::~YRichText() +{ + // NOP +} + + +void YRichText::setValue( const std::string & newValue ) +{ + priv->text = newValue; +} + + +std::string YRichText::value() const +{ + return priv->text; +} + + +bool YRichText::plainTextMode() const +{ + return priv->plainTextMode; +} + + +void YRichText::setPlainTextMode( bool plainTextMode ) +{ + priv->plainTextMode = plainTextMode; +} + + +bool YRichText::autoScrollDown() const +{ + return priv->autoScrollDown; +} + + +void YRichText::setAutoScrollDown( bool autoScrollDown ) +{ + priv->autoScrollDown = autoScrollDown; +} + + +bool YRichText::shrinkable() const +{ + return priv->shrinkable; +} + + +void YRichText::setShrinkable( bool shrinkable ) +{ + priv->shrinkable = shrinkable; +} + + +const YPropertySet & +YRichText::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Value the text content + * @property std::string Text the text content + */ + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Text, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YRichText::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.stringVal() ); + else if ( propertyName == YUIProperty_Text ) setValue( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YRichText::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else if ( propertyName == YUIProperty_Text ) return YPropertyValue( value() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YRichText.h b/src/YRichText.h new file mode 100644 index 0000000..149bfb3 --- /dev/null +++ b/src/YRichText.h @@ -0,0 +1,168 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRichText.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YRichText_h +#define YRichText_h + +#include +#include "YWidget.h" +#include "ImplPtr.h" + + +class YRichTextPrivate; + + +/** + * Text formatted with simple HTML-like tags, with "links" generating events. + **/ +class YRichText : public YWidget +{ +public: + + /** + * Constructor. + * + * 'plainTextMode' indicates that the text should be treated as plain text, + * i.e. any HTML-like tags in the text should not be interpreted in any + * way. + **/ + YRichText( YWidget * parent, + const std::string & text, + bool plainTextMode = false ); + + /** + * Destructor. + **/ + virtual ~YRichText(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YRichText"; } + + /** + * Change the text content of the RichText widget. + * + * Derived classes should overwrite this function, but call this base class + * function in the new function. + **/ + virtual void setValue( const std::string & newValue ); + + /** + * Return the text content of the RichText widget. + **/ + std::string value() const; + + /** + * Alias for setValue(). + **/ + void setText( const std::string & newText ) { setValue( newText ); } + + /** + * Alias for value(). + **/ + std::string text() const { return value(); } + + /** + * Return 'true' if this RichText widget is in "plain text" mode, i.e. does + * not try to interpret RichText/HTML tags. + **/ + bool plainTextMode() const; + + /** + * Set this RichText widget's "plain text" mode on or off. + * + * Derived classes may want to reimplement this, but they should call this + * base class function in the new function. + **/ + virtual void setPlainTextMode( bool on = true ); + + /** + * Return 'true' if this RichText widget should automatically scroll down + * when the text content is changed. This is useful for progress displays + * and log files. + **/ + bool autoScrollDown() const; + + /** + * Set this RichText widget's "auto scroll down" mode on or off. + * + * Derived classes may want to reimplement this, but they should call this + * base class function in the new function. + **/ + virtual void setAutoScrollDown( bool on = true ); + + /** + * Returns 'true' if this widget is "shrinkable", i.e. it should be very + * small by default. + **/ + bool shrinkable() const; + + /** + * Make this widget shrinkable, i.e. very small in layouts. + * + * This method is intentionally not virtual because it doesn't have any + * immediate effect; it is only needed in preferredWidth() / + * preferredHeight(). + **/ + void setShrinkable( bool shrinkable = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + +protected: + + ImplPtr priv; +}; + + +#endif // YRichText_h diff --git a/src/YRpmGroupsTree.cc b/src/YRpmGroupsTree.cc new file mode 100644 index 0000000..09e3941 --- /dev/null +++ b/src/YRpmGroupsTree.cc @@ -0,0 +1,283 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRpmGroupsTree.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YRpmGroupsTree.h" + +#include "Libyui_config.h" + +#define TEXTDOMAIN "rpm-groups" + + +YRpmGroupsTree::YRpmGroupsTree() + : YStringTree( TEXTDOMAIN ) +{ + bindtextdomain( TEXTDOMAIN, LOCALEDIR ); + bind_textdomain_codeset( TEXTDOMAIN, "utf8" ); +} + + +YRpmGroupsTree::~YRpmGroupsTree() +{ + // NOP +} + + +static const char *fallback_rpm_groups[] = +{ + "Amusements/Games/3D/Other", + "Amusements/Games/3D/Race", + "Amusements/Games/3D/Shoot", + "Amusements/Games/3D/Simulation", + "Amusements/Games/Action/Arcade", + "Amusements/Games/Action/Breakout", + "Amusements/Games/Action/Other", + "Amusements/Games/Action/Race", + "Amusements/Games/Action/Shoot", + "Amusements/Games/Board/Card", + "Amusements/Games/Board/Chess", + "Amusements/Games/Board/Other", + "Amusements/Games/Board/Pool", + "Amusements/Games/Board/Puzzle", + "Amusements/Games/Logic", + "Amusements/Games/Other", + "Amusements/Games/RPG", + "Amusements/Games/Strategy/Other", + "Amusements/Games/Strategy/Real Time", + "Amusements/Games/Strategy/Turn Based", + "Amusements/Toys/Background", + "Amusements/Toys/Clocks", + "Amusements/Toys/Graphics", + "Amusements/Toys/Other", + "Amusements/Toys/Screensavers", + "Development/Languages/C and C++", + "Development/Languages/Fortran", + "Development/Languages/Java", + "Development/Languages/Other", + "Development/Languages/Perl", + "Development/Languages/Python", + "Development/Languages/Scheme", + "Development/Languages/Tcl", + "Development/Libraries/C and C++", + "Development/Libraries/Cross", + "Development/Libraries/GNOME", + "Development/Libraries/Java", + "Development/Libraries/KDE", + "Development/Libraries/Other", + "Development/Libraries/Parallel", + "Development/Libraries/Perl", + "Development/Libraries/Python", + "Development/Libraries/Tcl", + "Development/Libraries/X11", + "Development/Libraries/YaST", + "Development/Tools/Building", + "Development/Tools/Debuggers", + "Development/Tools/Doc Generators", + "Development/Tools/GUI Builders", + "Development/Tools/IDE", + "Development/Tools/Navigators", + "Development/Tools/Other", + "Development/Tools/Version Control", + "Documentation/Howto", + "Documentation/Man", + "Documentation/Other", + "Documentation/SuSE", + "Hardware/Fax", + "Hardware/ISDN", + "Hardware/Joystick", + "Hardware/Mobile", + "Hardware/Modem", + "Hardware/Other", + "Hardware/Palm", + "Hardware/Printing", + "Hardware/Psion", + "Hardware/Radio", + "Hardware/Scanner", + "Hardware/TV", + "Hardware/UPS", + "Productivity/Archiving/Backup", + "Productivity/Archiving/Compression", + "Productivity/Clustering/Computing", + "Productivity/Clustering/HA", + "Productivity/Databases/Clients", + "Productivity/Databases/Servers", + "Productivity/Databases/Tools", + "Productivity/Editors/Emacs", + "Productivity/Editors/Other", + "Productivity/Editors/Vi", + "Productivity/File utilities", + "Productivity/Graphics/3D Editors", + "Productivity/Graphics/Bitmap Editors", + "Productivity/Graphics/CAD", + "Productivity/Graphics/Convertors", + "Productivity/Graphics/Other", + "Productivity/Graphics/Vector Editors", + "Productivity/Graphics/Viewers", + "Productivity/Graphics/Visualization/Graph", + "Productivity/Graphics/Visualization/Other", + "Productivity/Graphics/Visualization/Raytracers", + "Productivity/Hamradio/Fax", + "Productivity/Hamradio/Logging", + "Productivity/Hamradio/Morse", + "Productivity/Hamradio/Other", + "Productivity/Hamradio/Packet", + "Productivity/Hamradio/Psk31", + "Productivity/Hamradio/Satellite", + "Productivity/Multimedia/CD/Grabbers", + "Productivity/Multimedia/CD/Players", + "Productivity/Multimedia/CD/Record", + "Productivity/Multimedia/Other", + "Productivity/Multimedia/Sound/Editors and Convertors", + "Productivity/Multimedia/Sound/Midi", + "Productivity/Multimedia/Sound/Mixers", + "Productivity/Multimedia/Sound/Players", + "Productivity/Multimedia/Sound/Utilities", + "Productivity/Multimedia/Sound/Visualization", + "Productivity/Multimedia/Video/Editors and Convertors", + "Productivity/Multimedia/Video/Players", + "Productivity/Networking/AOLInstantMessenger", + "Productivity/Networking/Archie", + "Productivity/Networking/Boot/Clients", + "Productivity/Networking/Boot/Servers", + "Productivity/Networking/Boot/Utilities", + "Productivity/Networking/DNS/Servers", + "Productivity/Networking/DNS/Utilities", + "Productivity/Networking/Diagnostic", + "Productivity/Networking/Email/Clients", + "Productivity/Networking/Email/Mailinglists", + "Productivity/Networking/Email/Servers", + "Productivity/Networking/Email/Utilities", + "Productivity/Networking/Ftp/Clients", + "Productivity/Networking/Ftp/Servers", + "Productivity/Networking/H323/Clients", + "Productivity/Networking/H323/Servers", + "Productivity/Networking/H323/Utilities", + "Productivity/Networking/ICQ", + "Productivity/Networking/IRC", + "Productivity/Networking/LDAP/Clients", + "Productivity/Networking/LDAP/Servers", + "Productivity/Networking/NFS", + "Productivity/Networking/NIS", + "Productivity/Networking/Napster", + "Productivity/Networking/News/Clients", + "Productivity/Networking/News/Servers", + "Productivity/Networking/News/Utilities", + "Productivity/Networking/Novell", + "Productivity/Networking/Other", + "Productivity/Networking/PPP", + "Productivity/Networking/Radius/Clients", + "Productivity/Networking/Radius/Servers", + "Productivity/Networking/Routing", + "Productivity/Networking/SSH", + "Productivity/Networking/Samba", + "Productivity/Networking/Security", + "Productivity/Networking/System", + "Productivity/Networking/Talk/Clients", + "Productivity/Networking/Talk/Servers", + "Productivity/Networking/Web/Browsers", + "Productivity/Networking/Web/Frontends", + "Productivity/Networking/Web/Proxy", + "Productivity/Networking/Web/Servers", + "Productivity/Networking/Web/Utilities", + "Productivity/Office/Dictionary", + "Productivity/Office/Finance", + "Productivity/Office/Organizers", + "Productivity/Office/Other", + "Productivity/Office/Spreadsheets", + "Productivity/Office/Suite", + "Productivity/Other", + "Productivity/Publishing/DocBook", + "Productivity/Publishing/HTML/Editors", + "Productivity/Publishing/HTML/Tools", + "Productivity/Publishing/Other", + "Productivity/Publishing/PDF", + "Productivity/Publishing/PS", + "Productivity/Publishing/Presentation", + "Productivity/Publishing/SGML", + "Productivity/Publishing/TeX/Base", + "Productivity/Publishing/TeX/Fonts", + "Productivity/Publishing/TeX/Frontends", + "Productivity/Publishing/TeX/Utilities", + "Productivity/Publishing/Texinfo", + "Productivity/Publishing/Troff", + "Productivity/Publishing/Word", + "Productivity/Publishing/XML", + "Productivity/Scientific/Astronomy", + "Productivity/Scientific/Chemistry", + "Productivity/Scientific/Electronics", + "Productivity/Scientific/Math", + "Productivity/Scientific/Other", + "Productivity/Scientific/Physics", + "Productivity/Security", + "Productivity/Text/Convertors", + "Productivity/Text/Spell", + "Productivity/Text/Utilities", + "SuSE internal", + "System/Base", + "System/Benchmark", + "System/Boot", + "System/Console", + "System/Daemons", + "System/Emulators/Other", + "System/Emulators/PC", + "System/Fhs", + "System/Filesystems", + "System/GUI/GNOME", + "System/GUI/KDE", + "System/GUI/Other", + "System/I18n/Chinesse", + "System/I18n/Japanesse", + "System/I18n/Korean", + "System/Kernel", + "System/Libraries", + "System/Monitoring", + "System/Packages", + "System/Shells", + "System/Sound Daemons", + "System/X11/Displaymanagers", + "System/X11/Fonts", + "System/X11/Icons", + "System/X11/Servers/XF86_3", + "System/X11/Servers/XF86_4", + "System/X11/Terminals", + "System/X11/Utilities", + "System/YaST", + "Unsorted" +}; + +#define DIM(ARRAY) ( sizeof( ARRAY ) / sizeof( ARRAY[0] ) ) + + +void +YRpmGroupsTree::addFallbackRpmGroups() +{ + for ( unsigned i=0; i < DIM( fallback_rpm_groups ); i++ ) + { + addRpmGroup( fallback_rpm_groups[ i ] ); + } + +#if 0 + logTree(); +#endif +} diff --git a/src/YRpmGroupsTree.h b/src/YRpmGroupsTree.h new file mode 100644 index 0000000..d3a0d29 --- /dev/null +++ b/src/YRpmGroupsTree.h @@ -0,0 +1,79 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YRpmGroupsTree.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YRpmGroupsTree_h +#define YRpmGroupsTree_h + + +#include "YStringTree.h" + + +/** + * Efficient storage for RPM group tags + **/ +class YRpmGroupsTree: public YStringTree +{ +public: + + /** + * Constructor. + **/ + + YRpmGroupsTree(); + + /** + * Destructor. + **/ + virtual ~YRpmGroupsTree(); + + /** + * Insert an RPM group into this tree if not already present. + * Splits the RPM group string ("abc/def/ghi") and creates tree items for + * each level as required. + * Returns the tree entry for this RPM group. + **/ + YStringTreeItem * addRpmGroup( const std::string & rpmGroup ) + { return addBranch( rpmGroup, '/' ); } + + /** + * Returns the complete (untranslated) RPM group tag string for 'node'. + **/ + std::string rpmGroup( const YStringTreeItem * node ) + { return origPath( node, '/', false ); } + + /** + * Returns the complete translated RPM group tag string for 'node'. + **/ + std::string translatedRpmGroup( const YStringTreeItem * node ) + { return translatedPath( node, '/', false ); } + + /** + * Add a predefined set of RPM groups + **/ + void addFallbackRpmGroups(); +}; + + + +#endif // YRpmGroupsTree_h diff --git a/src/YSelectionBox.cc b/src/YSelectionBox.cc new file mode 100644 index 0000000..a7062a3 --- /dev/null +++ b/src/YSelectionBox.cc @@ -0,0 +1,153 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSelectionBox.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YSelectionBox.h" +#include "YUISymbols.h" +#include "YUIException.h" + + +struct YSelectionBoxPrivate +{ + YSelectionBoxPrivate() + : shrinkable( false ) + , immediateMode( false ) + {} + + bool shrinkable; + bool immediateMode; +}; + + + + +YSelectionBox::YSelectionBox( YWidget * parent, const std::string & label ) + : YSelectionWidget( parent, label, + true ) // enforceSingleSelection + , priv( new YSelectionBoxPrivate() ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); + +} + + +YSelectionBox::~YSelectionBox() +{ + // NOP +} + + +bool YSelectionBox::shrinkable() const +{ + return priv->shrinkable; +} + + +void YSelectionBox::setShrinkable( bool shrinkable ) +{ + priv->shrinkable = shrinkable; +} + + +bool YSelectionBox::immediateMode() const +{ + return priv->immediateMode; +} + + +void YSelectionBox::setImmediateMode( bool immediateMode ) +{ + priv->immediateMode = immediateMode; + + if ( immediateMode ) + setNotify( true ); +} + + +const YPropertySet & +YSelectionBox::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property itemID Value The currently selected item + * @property itemID CurrentItem The currently selected item + * @property itemList Items All items + * @property std::string Label Caption above the selection box + * @property std::string IconPath Base path for icons + */ + propSet.add( YProperty( YUIProperty_Value, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentItem, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YSelectionBox::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) return false; // Needs special handling + else if ( propertyName == YUIProperty_CurrentItem ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YSelectionBox::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_CurrentItem ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YSelectionBox.h b/src/YSelectionBox.h new file mode 100644 index 0000000..7fc4fb8 --- /dev/null +++ b/src/YSelectionBox.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSelectionBox.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSelectionBox_h +#define YSelectionBox_h + +#include "YSelectionWidget.h" + +class YSelectionBoxPrivate; + + +/** + * Selection box: List box that displays a (scrollable) list of items from + * which the user can select exactly one. Each item has a label text and an + * optional icon (*). + * + * This widget displays a number of items at once (as screen space permits). If + * there is little screen space, you might consider using a ComboBox instead + * which (in non-editable mode which is the default) displays just one item + * (the selected item) right away and the others in a pop-up dialog upon mouse + * click or keypress. + * + * The selection box also has a caption label that is + * displayed above the list. The hotkey displayed in that caption label will + * move the keyboard focus into the list. + * + * If multiple columns are needed, use the YTable widget instead. + * For tree-like structures, use the YTree widget. + * Use YMultiSelectionBox if more than one item can be selected. + * + * (*) Not all UIs (in particular not text-based UIs) support displaying icons, + * so an icon should never be an exclusive means to display any kind of + * information. + **/ +class YSelectionBox : public YSelectionWidget +{ +protected: + + /** + * Constructor. + **/ + YSelectionBox( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YSelectionBox(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YSelectionBox"; } + + /** + * Return 'true' if this SelectionBox should be very small. + **/ + bool shrinkable() const; + + /** + * Make this SelectionBox very small. This will take effect only upon the + * next geometry management run. + * + * Derived classes can overwrite this, but should call this base class + * function in the new function. + **/ + virtual void setShrinkable( bool shrinkable = true ); + + /** + * Deliver even more events than with notify() set. + * + * For YSelectionBox, this is relevant mostly for the NCurses UI: + * + * In graphical UIs like the Qt UI, the user can use the mouse to select an + * item in a selection box. With notify() set, this will send an event + * right away (i.e., it will make UserInput and related return, while + * normally it would only return when the user clicks a PushButton). + * + * In the NCurses UI, there is no mouse, so the user has to use the cursor + * keys to move to the item he wants to select. In immediateMode(), every + * cursor key press will make the selection box send an event. Without + * immediateMode(), the NCSelectionBox will wait until the user hits the + * [Return] key until an event is sent. Depending on what the application + * does upon each selection box event, immediateMode() might make the + * application less responsive. + **/ + bool immediateMode() const; + + /** + * Set immediateMode() on or off. + **/ + void setImmediateMode( bool on = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_CurrentItem; } + + +private: + + ImplPtr priv; +}; + + +#endif // YSelectionBox_h diff --git a/src/YSelectionWidget.cc b/src/YSelectionWidget.cc new file mode 100644 index 0000000..0ac1901 --- /dev/null +++ b/src/YSelectionWidget.cc @@ -0,0 +1,506 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSelectionWidget.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include +#include "YSelectionWidget.h" +#include "YUIException.h" +#include "YApplication.h" + + +struct YSelectionWidgetPrivate +{ + YSelectionWidgetPrivate( const std::string & label, + bool enforceSingleSelection, + bool recursiveSelection ) + : label( label ) + , enforceSingleSelection( enforceSingleSelection ) + , recursiveSelection ( recursiveSelection ) + {} + + std::string label; + bool enforceSingleSelection; + bool recursiveSelection; + std::string iconBasePath; + YItemCollection itemCollection; +}; + + + + +YSelectionWidget::YSelectionWidget( YWidget * parent, + const std::string & label, + bool enforceSingleSelection , + bool recursiveSelection ) + : YWidget( parent ) + , priv( new YSelectionWidgetPrivate( label, enforceSingleSelection, recursiveSelection ) ) +{ + YUI_CHECK_NEW( priv ); + + if ( enforceSingleSelection && recursiveSelection ) + YUI_THROW( YUIException( "recursiveSelection is only available for multiSelection Widgets.")); + +} + + +YSelectionWidget::~YSelectionWidget() +{ + deleteAllItems(); +} + + +void YSelectionWidget::deleteAllItems() +{ + YItemIterator it = itemsBegin(); + + while ( it != itemsEnd() ) + { + YItem * item = *it; + ++it; + delete item; + + // No need to check for item->hasChildren() and iterate recursively + // over the children: The item will take care of its children in its + // destructor. + } + + priv->itemCollection.clear(); +} + + +std::string YSelectionWidget::label() const +{ + return priv->label; +} + + +void YSelectionWidget::setLabel( const std::string & newLabel ) +{ + priv->label = newLabel; +} + + +bool YSelectionWidget::enforceSingleSelection() const +{ + return priv->enforceSingleSelection; +} + +bool YSelectionWidget::recursiveSelection() const +{ + return priv->recursiveSelection; +} + + + +void YSelectionWidget::setEnforceSingleSelection( bool enforceSingleSelection ) +{ + priv->enforceSingleSelection = enforceSingleSelection; +} + + +void YSelectionWidget::setIconBasePath( const std::string & basePath ) +{ + priv->iconBasePath = basePath; +} + + +std::string YSelectionWidget::iconBasePath() const +{ + return priv->iconBasePath; +} + + +std::string YSelectionWidget::iconFullPath( const std::string & iconName ) const +{ + std::string fullPath; + + if ( ! iconName.empty() ) + { + if ( iconName[0] == '/' ) + return iconName; + + if ( priv->iconBasePath.empty() || + priv->iconBasePath[0] != '/' ) + { + return YUI::yApp()->iconLoader()->findIcon( iconName ); + } + + fullPath += priv->iconBasePath + "/" + iconName; + } + + return fullPath; +} + + +std::string YSelectionWidget::iconFullPath( YItem * item ) const +{ + if ( item ) + return iconFullPath( item->iconName() ); + else + return ""; +} + + +void YSelectionWidget::addItem( YItem * item ) +{ + YUI_CHECK_PTR( item ); + + if ( item->parent() ) + { + YUI_THROW( YUIException( "Item already owned by parent item -" + " call addItem() only for toplevel items!" ) ); + } + + // Add the new item to the item list + + priv->itemCollection.push_back( item ); + item->setIndex( priv->itemCollection.size() - 1 ); + + // yuiDebug() << "Adding item \"" << item->label() << "\"" << endl; + + // + // Enforce single selection (if applicable) + // + + if ( priv->enforceSingleSelection ) + { + YItem* newItemSelected = NULL; + if ( item->selected() ) + { + newItemSelected = item; + } + else + { + newItemSelected = findSelectedItem( item->childrenBegin(), + item->childrenEnd() ); + } + + if ( newItemSelected ) + { + // This looks expensive, but it is not: Even though deselectAllItems() + // searches the complete item list and de select all. + // + // This prevents the calling application does this systematically wrong + // and sets the "selected" flag for more items or children + deselectAllItems(); + newItemSelected->setSelected( true ); + } + + + // Make sure there is one item selected initially. + // + // If any other subsequently added items are to be selected, they will + // override this initial selection. + + if ( priv->itemCollection.size() == 1 ) + item->setSelected( true ); + } +} + + +void YSelectionWidget::addItem( const std::string & itemLabel, + const std::string & iconName, + bool selected ) +{ + YItem * item = new YItem( itemLabel, iconName, selected ); + YUI_CHECK_NEW( item ); + addItem( item ); +} + + +void YSelectionWidget::addItem( const std::string & itemLabel, bool selected ) +{ + addItem( itemLabel, "", selected ); +} + + +void YSelectionWidget::addItems( const YItemCollection & itemCollection ) +{ + OptimizeChanges below( *this ); // Delay screen updates until this block is left + priv->itemCollection.reserve( priv->itemCollection.size() + itemCollection.size() ); + + for ( YItemConstIterator it = itemCollection.begin(); + it != itemCollection.end(); + ++it ) + { + addItem( *it ); + + // No need to check for (*it)->hasChildren() and iterate recursively + // over the children: Any children of this item simply remain in this + // item's YItemCollection. + } +} + + +YItemIterator +YSelectionWidget::itemsBegin() +{ + return priv->itemCollection.begin(); +} + +YItemConstIterator +YSelectionWidget::itemsBegin() const +{ + return priv->itemCollection.begin(); +} + + +YItemIterator +YSelectionWidget::itemsEnd() +{ + return priv->itemCollection.end(); +} + + +YItemConstIterator +YSelectionWidget::itemsEnd() const +{ + return priv->itemCollection.end(); +} + + +bool YSelectionWidget::hasItems() const +{ + return ! priv->itemCollection.empty(); +} + + +int YSelectionWidget::itemsCount() const +{ + return priv->itemCollection.size(); +} + + +YItem * +YSelectionWidget::firstItem() const +{ + if ( priv->itemCollection.empty() ) + return 0; + else + return priv->itemCollection.front(); +} + + +YItem * +YSelectionWidget::itemAt( int index ) const +{ + if ( index < 0 || index >= (int) priv->itemCollection.size() ) + return 0; + + return priv->itemCollection[ index ]; +} + + +YItem * +YSelectionWidget::selectedItem() +{ + return findSelectedItem( itemsBegin(), itemsEnd() ); +} + + +YItem * +YSelectionWidget::findSelectedItem( YItemConstIterator begin, + YItemConstIterator end ) +{ + for ( YItemConstIterator it = begin; it != end; ++it ) + { + const YItem * item = *it; + + if ( item->selected() ) + { + return *it; + } + if ( item->hasChildren() ) + { + YItem * selectedItem = findSelectedItem( item->childrenBegin(), + item->childrenEnd() ); + if ( selectedItem ) + { + // yuiDebug() << "Selected item: \"" << selectedItem->label() << "\"" << endl; + return selectedItem; + } + } + } + + return 0; +} + + +YItemCollection +YSelectionWidget::selectedItems() +{ + YItemCollection selectedItems; + findSelectedItems( selectedItems, itemsBegin(), itemsEnd() ); + + return selectedItems; +} + + +void +YSelectionWidget::findSelectedItems( YItemCollection & selectedItems, + YItemConstIterator begin, + YItemConstIterator end ) +{ + for ( YItemConstIterator it = begin; it != end; ++it ) + { + YItem * item = *it; + + if ( item->selected() ) + selectedItems.push_back( item ); + + if ( item->hasChildren() ) + { + findSelectedItems( selectedItems, + item->childrenBegin(), + item->childrenEnd() ); + } + } +} + + +bool YSelectionWidget::hasSelectedItem() +{ + return selectedItem() != 0; +} + + +void YSelectionWidget::selectItem( YItem * item, bool selected ) +{ + YUI_CHECK_PTR( item ); + + if ( ! itemsContain( item ) ) + YUI_THROW( YUIException( "Item does not belong to this widget" ) ); + + if ( priv->enforceSingleSelection && selected ) + { + YItem * oldSelectedItem = selectedItem(); + + if ( oldSelectedItem ) + oldSelectedItem->setSelected( false ); + } + + + if ( recursiveSelection() && item->hasChildren() ) + { + for ( YItemIterator it = item->childrenBegin(); it != item->childrenEnd(); ++it ) + { + YItem * item = *it; + selectItem(item, selected ); + item->setSelected( selected ); + } + } + + item->setSelected( selected ); +} + + +bool YSelectionWidget::itemsContain( YItem * wantedItem ) const +{ + return itemsContain( wantedItem, itemsBegin(), itemsEnd() ); +} + + + +bool +YSelectionWidget::itemsContain( YItem * wantedItem, + YItemConstIterator begin, + YItemConstIterator end ) const +{ + for ( YItemConstIterator it = begin; it != end; ++it ) + { + const YItem * item = *it; + + if ( item == wantedItem ) + return true; + + if ( item->hasChildren() ) + { + if ( itemsContain( wantedItem, + item->childrenBegin(), + item->childrenEnd() ) ) + { + return true; + } + } + } + + return false; +} + + +void YSelectionWidget::deselectAllItems() +{ + deselectAllItems( itemsBegin(), itemsEnd() ); +} + + +void YSelectionWidget::deselectAllItems( YItemIterator begin, + YItemIterator end ) +{ + for ( YItemConstIterator it = begin; it != end; ++it ) + { + YItem * item = *it; + + item->setSelected( false ); + + if ( item->hasChildren() ) + deselectAllItems( item->childrenBegin(), item->childrenEnd() ); + } +} + + +YItem * +YSelectionWidget::findItem( const std::string & wantedItemLabel ) const +{ + return findItem( wantedItemLabel, itemsBegin(), itemsEnd() ); +} + + +YItem * +YSelectionWidget::findItem( const std::string & wantedItemLabel, + YItemConstIterator begin, + YItemConstIterator end ) const +{ + for ( YItemConstIterator it = begin; it != end; ++it ) + { + YItem * item = *it; + + if ( item->label() == wantedItemLabel ) + return item; + + if ( item->hasChildren() ) + { + YItem * wantedItem = findItem( wantedItemLabel, + item->childrenBegin(), + item->childrenEnd() ); + if ( wantedItem ) + return wantedItem; + } + } + + return 0; +} diff --git a/src/YSelectionWidget.h b/src/YSelectionWidget.h new file mode 100644 index 0000000..abbdfb4 --- /dev/null +++ b/src/YSelectionWidget.h @@ -0,0 +1,341 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSelectionWidget.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSelectionWidget_h +#define YSelectionWidget_h + +#include "YWidget.h" +#include "YItem.h" +#include "ImplPtr.h" + +class YSelectionWidgetPrivate; + +/** + * Base class for various kinds of multi-value widgets. + * - YSelectionBox, YMultiSelectionBox, YComboBox + * - YContextMenu, YMenuButton + * - YTable + * - YTree + * - YDumbTab + **/ +class YSelectionWidget : public YWidget +{ +protected: + + /** + * Constructor. + * + * 'singleSelectionMode' indicates if this base class should enforce single + * selection when items are added or when items are selected from the + * application. Note that single selection can also mean that no item is + * selected. + **/ + YSelectionWidget( YWidget * parent, + const std::string & label, + bool enforceSingleSelection, + bool recurisveSelection = false ); + +public: + /** + * Destructor. + **/ + virtual ~YSelectionWidget(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YSelectionWidget"; } + + /** + * Return this widget's label (the caption above the item list). + **/ + std::string label() const; + + /** + * Change this widget's label (the caption above the item list). + * + * Derived classes should overwrite this function, but they should call + * this base class function in the new implementation. + **/ + virtual void setLabel( const std::string & newLabel ); + + /** + * Add one item. This widget assumes ownership of the item object and will + * delete it in its destructor. + * + * NOTE: For tree items, call this only for the toplevel items; all + * non-toplevel items are already owned by their respective parent + * items. Adding them to the parent widget will clash with this ownership. + * + * Derived classes can overwrite this function, but they should call this + * base class function in the new implementation. + **/ + virtual void addItem( YItem * item_disown ); + + /** + * Overloaded for convenience: Add an item by string. + **/ + void addItem( const std::string & itemLabel, bool selected = false ); + + /** + * Overloaded for convenience: Add an item with a text and an icon. + * Note that not all UIs can display icons. + **/ + void addItem( const std::string & itemLabel, + const std::string & iconName, + bool selected = false ); + + /** + * Add multiple items. For some UIs, this can be more efficient than + * calling addItem() multiple times. + **/ + virtual void addItems( const YItemCollection & itemCollection ); + + /** + * Delete all items. + * + * Derived classes can overwrite this function, but they should call this + * base class function in the new implementation. + **/ + virtual void deleteAllItems(); + + /** + * Delete all items and add new items. + **/ + void setItems( const YItemCollection & itemCollection ) + { deleteAllItems(); addItems( itemCollection ); } + + /** + * Return an iterator that points to the first item. + * + * For YSelectionWidgets that can have tree structures, this iterator will + * iterate over the toplevel items. + * + * Important: Don't use this iterator to iterate over all items and check + * their "selected" state; that information might not always be up to + * date. Use the dedicated functions for that. + **/ + YItemIterator itemsBegin(); + YItemConstIterator itemsBegin() const; + + /** + * Return an iterator that points behind the last item. + **/ + YItemIterator itemsEnd(); + YItemConstIterator itemsEnd() const; + + /** + * Return 'true' if this widget has any items. + **/ + bool hasItems() const; + + /** + * Return the number of items. + * + * For YSelectionWidgets that can have tree structures, this returns the + * number of toplevel items. + **/ + int itemsCount() const; + + /** + * Return the first item or 0 if there is none. + **/ + YItem * firstItem() const; + + /** + * Return the (first) selected item or 0 if none is selected. + **/ + virtual YItem * selectedItem(); + + /** + * Return all selected items. This is mostly useful for derived classes + * that allow selecting multiple items. + * + * This function does not transfer ownership of those items to the caller, + * so don't try to delete them! + **/ + virtual YItemCollection selectedItems(); + + /** + * Return 'true' if any item is selected. + **/ + bool hasSelectedItem(); + + /** + * Select or deselect an item. + * + * Notice that this is different from YItem::setSelected() because unlike + * the latter function, this function informs the parent widget of the + * selection change. + * + * If only one item can be selected at any time (single selection), the + * derived class will make sure to deselect any previous selection, if + * applicable. + * + * Derived classes should overwrite this function, but they should call + * this base class function at the new function's start (this will also + * check if the item really belongs to this widget and throw an exception + * if not). + **/ + virtual void selectItem( YItem * item, bool selected = true ); + + /** + * Deselect all items. + * + * Derived classes can overwrite this function, but they should call this + * base class function in the new implementation. + **/ + virtual void deselectAllItems(); + + /** + * Set this widget's base path where to look up icons. + * If this is a relative path, YUI::qApp()->iconBasePath() is prepended. + **/ + void setIconBasePath( const std::string & basePath ); + + /** + * Return this widget's base path where to look up icons + * as set with setIconBasePath(). + **/ + std::string iconBasePath() const; + + /** + * Return the full path + file name for the specified icon name. + * If iconBasePath is non-empty, it is prepended to the icon name. + * Otherwise, YUI::yApp()->iconLoader() and its icon search paths + * is used find the icon in one of them + * + * If 'iconName' is empty, this will return an empty string. + **/ + std::string iconFullPath( const std::string & iconName ) const; + + /** + * Return the full path + file name for the icon of the specified item. + * If iconBasePath is non-empty, it is prepended to the item's iconName. + * Otherwise, YUI::yApp()->iconLoader() and its icon search paths + * is used find the icon in one of them + * + * If 'item' does not have an iconName specified, this will return an empty + * string. + **/ + std::string iconFullPath( YItem * item ) const; + + /** + * Return 'true' if this widget's items contain the specified item. + **/ + bool itemsContain( YItem * item ) const; + + /** + * Find the (first) item with the specified label. + * Return 0 if there is no item with that label. + **/ + YItem * findItem( const std::string & itemLabel ) const; + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + +protected: + + /** + * Set single selection mode on or off. In single selection mode, only one + * item can be selected at any time. + * + * If set, this base class enforces this when items are added or when items + * are selected from the application. Note that single selection can also + * mean that no item is selected. + **/ + void setEnforceSingleSelection( bool on ); + + /** + * Return 'true' if this base class should enforce single selection. + **/ + bool enforceSingleSelection() const; + + /** + * Return 'true' if this base class should select children recursively. + **/ + bool recursiveSelection() const; + + /** + * Recursively try to find the first selected item between iterators + * 'begin' and 'end'. Return that item or 0 if there is none. + **/ + YItem * findSelectedItem( YItemConstIterator begin, + YItemConstIterator end ); + + /** + * Recursively find all selected items between iterators 'begin' and 'end' + * and add each of them to the 'selectedItems' YItemCollection. + **/ + void findSelectedItems( YItemCollection & selectedItems, + YItemConstIterator begin, + YItemConstIterator end ); + + /** + * Recursively deselect all items between iterators 'begin' and 'end'. + **/ + void deselectAllItems( YItemIterator begin, + YItemIterator end ); + /** + * Recursively try to find an item with label 'wantedItemLabel' between + * iterators 'begin' and 'end'. Return that item or 0 if there is none. + **/ + YItem * findItem ( const std::string & wantedItemLabel, + YItemConstIterator begin, + YItemConstIterator end ) const; + + /** + * Recursively check if 'wantedItem' is between iterators 'begin' and + * 'end'. + **/ + bool itemsContain ( YItem * wantedItem, + YItemConstIterator begin, + YItemConstIterator end ) const; + /** + * Return the item at index 'index' (from 0) + * or 0 if there is no such item. + **/ + YItem * itemAt( int index ) const; + + +private: + + ImplPtr priv; +}; + + +#endif // YSelectionWidget_h diff --git a/src/YSettings.cc b/src/YSettings.cc new file mode 100644 index 0000000..1afc1ec --- /dev/null +++ b/src/YSettings.cc @@ -0,0 +1,200 @@ +/* + Copyright (c) 2012 Björn Esser + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +/*-/ + + File: YSettings.cc + + Author: Björn Esser + +/-*/ + +#include "YSettings.h" +#include "YUIException.h" + +#define YUILogComponent "ui" +#include "YUILog.h" +#include "Libyui_config.h" + +using std::endl; + +std::string YSettings::_progDir = ""; +std::string YSettings::_iconDir = ""; +std::string YSettings::_themeDir = ""; +std::string YSettings::_localeDir = ""; +std::string YSettings::_loadedUI = ""; + +YSettings::YSettings() +{ +} + +YSettings::~YSettings () +{ +} + +void YSettings::setProgDir( std::string directory ) +{ + if ( _progDir.empty() ) + { + _progDir = directory; + yuiMilestone () << "Set progDir to \"" << directory << "\"" << endl; + yuiMilestone () << "progDir is now locked." << endl; + } + else + { + yuiMilestone () << "Can't set progDir to \"" << directory << "\"" << endl; + yuiMilestone () << "It is locked to: \"" << _progDir << "\"" << endl; + YUI_THROW ( YUIException ( "progSubDir is locked to: \"" + _progDir + "\"" ) ); + } +} + +std::string YSettings::progDir () +{ + yuiMilestone () << "progDir: \"" << _progDir << "\"" << endl; + + return _progDir; +} + + +void YSettings::setIconDir( std::string directory ) +{ + if ( _iconDir.empty() ) + { + _iconDir = directory; + yuiMilestone () << "Set iconDir to \"" << directory << "\"" << endl; + yuiMilestone () << "iconDir is now locked." << endl; + } + else + { + yuiMilestone () << "Can't set iconDir to \"" << directory << "\"" << endl; + yuiMilestone () << "It is locked to: \"" << _iconDir << "\"" << endl; + YUI_THROW ( YUIException ( "progIconDir is locked to: \"" + _iconDir + "\"" ) ); + } +} + +std::string YSettings::iconDir () +{ + if (_iconDir.size()) + { + yuiMilestone () << "iconDir: \"" << _iconDir << "\"" << endl; + return _iconDir; + } + else if (_progDir.size()) + return _progDir + "/icons/"; + + return THEMEDIR "/icons/"; +} + +void YSettings::setThemeDir( std::string directory ) +{ + if ( _themeDir.empty() ) + { + _themeDir = directory; + yuiMilestone () << "Set themeDir to \"" << directory << "\"" << endl; + yuiMilestone () << "themeDir is now locked." << endl; + } + else + { + yuiMilestone () << "Can't set themeDir to \"" << directory << "\"" << endl; + yuiMilestone () << "It is locked to: \"" << _themeDir << "\"" << endl; + YUI_THROW ( YUIException ( "themeDir is locked to: \"" + _themeDir + "\"" ) ); + } +} + +std::string YSettings::themeDir () +{ + if ( _themeDir.size() ) + { + yuiMilestone () << "themeDir: \"" << _themeDir << "\"" << endl; + return _themeDir; + } + else if ( _progDir.size() ) + { + //back compatibility if setProgSubDir is set to "/usr/share/YaST2" + return _progDir + "/theme/current/wizard/"; + } + + return THEMEDIR "/current/wizard/"; +} + + +void YSettings::setLocaleDir( std::string directory ) +{ + if ( _localeDir.empty() ) + { + _localeDir = directory; + yuiMilestone () << "Set localeDir to \"" << directory << "\"" << endl; + yuiMilestone () << "localeDir is now locked." << endl; + } + else + { + yuiMilestone () << "Can't set localeDir to \"" << directory << "\"" << endl; + yuiMilestone () << "It is locked to: \"" << _localeDir << "\"" << endl; + YUI_THROW ( YUIException ( "localeDir is locked to: \"" + _localeDir + "\"" ) ); + } +} + +std::string YSettings::localeDir () +{ + if ( _localeDir.size() ) + { + yuiMilestone () << "localeDir: \"" << _localeDir << "\"" << endl; + return _localeDir; + } + else if ( _progDir.size() ) + { + //back compatibility if ProgDir is set to "/usr/share/YaST2" + return _progDir + "/locale/"; + } + + return "/usr/share/locale/"; +} + +void YSettings::loadedUI( std::string ui, bool force ) +{ + if ( _loadedUI.empty() || force ) + { + _loadedUI = ui; + yuiMilestone () << "Set loadedUI to \"" << ui << "\"" << endl; + yuiMilestone () << "loadedUI is now locked." << endl; + } + else + { + yuiMilestone () << "Can't set loadedUI to \"" << ui << "\"" << endl; + yuiMilestone () << "It is locked to: \"" << _loadedUI << "\"" << endl; + YUI_THROW ( YUIException ( "loadedUI is locked to: \"" + _loadedUI + "\"" ) ); + } +} + +void YSettings::loadedUI( std::string ui ) +{ + loadedUI( ui, false ); +} + +std::string YSettings::loadedUI () +{ + yuiMilestone () << "loadedUI: \"" << _loadedUI << "\"" << endl; + + return _loadedUI; +} diff --git a/src/YSettings.h b/src/YSettings.h new file mode 100644 index 0000000..a765bcc --- /dev/null +++ b/src/YSettings.h @@ -0,0 +1,139 @@ +/* + Copyright (c) 2012 Björn Esser + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR + THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +/*-/ + + File: YSettings.h + + Author: Björn Esser + +/-*/ + +#ifndef YSettings_h +#define YSettings_h + +#include + + +/** + * Predeclaration of YUILoader + **/ +class YUILoader; + +/** + * Settings for libyui + * + * This singleton-object hold some presets for libyui. + **/ +class YSettings +{ +friend YUILoader; + +public: + /** + * This can be used to set a subdir beneath PLUGINDIR or THEMEDIR, + * where your program stores a custom plugin or theme. + * + * Once this is set, it can't be altered. If you do so although an + * exception will be thrown. + **/ + static void setProgDir ( std::string directory ); + /** + * Returns the value of your program's subdir. + **/ + static std::string progDir (); + + /** + * This can be used to set a subdir ICONDIR, + * where your program stores a custom icons. + * + * Once this is set, it can't be altered. If you do so although an + * exception will be thrown. + **/ + static void setIconDir ( std::string directory ); + /** + * Returns the value of your program's icons subdir. + **/ + static std::string iconDir (); + + /** + * This can be used to set a subdir THEMEDIR, + * where your program stores a custom icons. + * + * Once this is set, it can't be altered. If you do so although an + * exception will be thrown. + **/ + static void setThemeDir ( std::string directory ); + /** + * Returns the value of your program's theme subdir. + **/ + static std::string themeDir (); + + /** + * This can be used to set a subdir LOCALEDIR, + * where your program stores translations + * + * Once this is set, it can't be altered. If you do so although an + * exception will be thrown. + **/ + static void setLocaleDir ( std::string directory ); + /** + * Returns the value of your program's locale subdir. + **/ + static std::string localeDir (); + + /** + * This can be used to set the loaded UI-backend. + * + * Once this is set, it can't be altered. If you do so although an + * exception will be thrown. + **/ + static void loadedUI ( std::string ui ); + /** + * Returns the value of the loaded UI-backend. + **/ + static std::string loadedUI (); + +protected: + /** + * This can be used to set the loaded UI-backend. + * + * Once this is set, it can't be altered, except if you force it. + * If you do so without force an exception will be thrown. + **/ + static void loadedUI ( std::string ui, bool force ); + +private: + static std::string _progDir; + static std::string _iconDir; + static std::string _themeDir; + static std::string _localeDir; + static std::string _loadedUI; + + YSettings (); + YSettings ( const YSettings& ); + ~YSettings (); +}; + +#endif // YSettings_h diff --git a/src/YShortcut.cc b/src/YShortcut.cc new file mode 100644 index 0000000..37041c7 --- /dev/null +++ b/src/YShortcut.cc @@ -0,0 +1,352 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YShortcut.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include // toupper(), tolower() +#include // strstr() + +#define YUILogComponent "ui-shortcuts" +#include "YUILog.h" + +#include "YShortcut.h" +#include "YPushButton.h" +#include "YDumbTab.h" + + +// Return the number of elements of an array of any type +#define DIM( ARRAY ) ( (int) ( sizeof( ARRAY)/( sizeof( ARRAY[0] ) ) ) ) + + +YShortcut::YShortcut( YWidget * shortcutWidget ) + : _widget( shortcutWidget ) +{ + _preferred = -1; + _shortcut = -1; + _distinctShortcutChars = -1; + _conflict = false; + _shortcutStringCached = false; + _cleanShortcutStringCached = false; + + YPushButton * button = dynamic_cast( shortcutWidget); + _isButton = ( button != 0 ); + + if ( _isButton ) + { + _isWizardButton = strstr( shortcutWidget->widgetClass(), "WizardButton" ); + + // yuiDebug() << shortcutWidget << ( _isWizardButton ? " is " : " is not " ) << "a wizard button" << endl; + } + else + { + _isWizardButton = 0; + } + + // yuiDebug() << shortcutWidget << ( _isButton ? " is " : " is not " ) << "a button" << endl; +} + + +YShortcut::~YShortcut() +{ +} + + +std::string +YShortcut::shortcutString() +{ + if ( ! _shortcutStringCached ) + { + _shortcutString = getShortcutString(); + _shortcutStringCached = true; + + // Note: We really need a separate variable here - an empty string + // might be a valid value! + } + + return _shortcutString; +} + + +std::string +YShortcut::cleanShortcutString() +{ + if ( ! _cleanShortcutStringCached ) + { + _cleanShortcutString = cleanShortcutString( shortcutString() ); + } + + return _cleanShortcutString; +} + + +std::string +YShortcut::cleanShortcutString( std::string shortcutString ) +{ + std::string::size_type pos = 0; + + while ( ( pos = findShortcutPos( shortcutString, pos ) ) != std::string::npos ) + { + shortcutString.erase( pos, ( std::string::size_type ) 1 ); + } + + return shortcutString; +} + + +char +YShortcut::preferred() +{ + if ( _preferred < 0 ) + { + _preferred = normalized( findShortcut( shortcutString() ) ); + } + + return (char) _preferred; +} + + +char +YShortcut::shortcut() +{ + if ( _shortcut < 0 ) + { + _shortcut = preferred(); + } + + return (char) _shortcut; +} + + +void +YShortcut::setShortcut( char newShortcut ) +{ + std::string str = cleanShortcutString(); + + if ( newShortcut != YShortcut::None ) + { + char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 }; + std::string::size_type pos = str.find_first_of( findme ); + + if ( pos == std::string::npos ) + { + yuiError() << "Can't find '<< " << newShortcut + << "' in " << widgetClass() + << " \"" << cleanShortcutString() << "\"" + << std::endl; + + return; + } + + str.insert( pos, + std::string( 1, shortcutMarker() ) ); // equivalent to 'std::string( "& " )' + } + + widget()->setShortcutString( str ); + + _shortcutStringCached = false; + _cleanShortcutStringCached = false; + _shortcut = newShortcut; +} + + +void +YShortcut::clearShortcut() +{ + setShortcut( YShortcut::None ); +} + + +int +YShortcut::distinctShortcutChars() +{ + if ( _distinctShortcutChars < 0 ) // cache this value - it's expensive! + { + // Create and initialize "contained" array - what possible shortcut + // characters are contained in that string? + + bool contained[ sizeof(char) << 8 ]; + + for ( int i=0; i < DIM( contained ); i++ ) + contained[i] = false; + + + // Mark characters as contained + + std::string clean = cleanShortcutString(); + + for ( std::string::size_type pos=0; pos < clean.length(); pos++ ) + { + if ( YShortcut::isValid( clean[ pos ] ) ) + contained[ (int) clean[ pos ] ] = true; + } + + + // Count number of contained characters + + _distinctShortcutChars=0; + + for ( int i=0; i < DIM( contained ); i++ ) + { + if ( contained[i] ) + { + _distinctShortcutChars++; + } + } + } + + return _distinctShortcutChars; +} + + +bool +YShortcut::hasValidShortcutChar() +{ + std::string clean = cleanShortcutString(); + + for ( std::string::size_type pos=0; pos < clean.length(); pos++ ) + { + if ( YShortcut::isValid( clean[ pos ] ) ) + return true; + } + + return false; +} + + +std::string +YShortcut::getShortcutString() +{ + return getShortcutString( widget() ); +} + + +std::string +YShortcut::getShortcutString( const YWidget * widget ) +{ + if ( ! widget ) + return std::string( "" ); + + return widget->shortcutString(); +} + + +std::string::size_type +YShortcut::findShortcutPos( const std::string & str, std::string::size_type pos ) +{ + while ( ( pos = str.find( shortcutMarker(), pos ) ) != std::string::npos ) + { + if ( pos+1 < str.length() ) + { + if ( str[ pos+1 ] == shortcutMarker() ) // escaped marker? ( "&&" ) + { + pos += 2; // skip this and search for more + } + else + return pos; + } + else + { + // A pathological case: The string ends with '& '. + // This is invalid anyway, but prevent endless loop even in this case. + return std::string::npos; + } + } + + return std::string::npos; // not found +} + + +char +YShortcut::findShortcut( const std::string & str, std::string::size_type pos ) +{ + pos = findShortcutPos( str, pos ); + + return pos == std::string::npos ? (char) 0 : str[ pos+1 ]; +} + + +bool +YShortcut::isValid( char c ) +{ + if ( c >= 'a' && c <= 'z' ) return true; + if ( c >= 'A' && c <= 'Z' ) return true; + if ( c >= '0' && c <= '9' ) return true; + return false; +} + + +char +YShortcut::normalized( char c ) +{ + if ( c >= 'a' && c <= 'z' ) return c - 'a' + 'A'; + if ( c >= 'A' && c <= 'Z' ) return c; + if ( c >= '0' && c <= '9' ) return c; + return (char) 0; +} + + + +std::string +YItemShortcut::getShortcutString() +{ + if ( ! _item ) + return ""; + + return _item->label(); +} + + +void +YItemShortcut::setShortcut( char newShortcut ) +{ + std::string str = cleanShortcutString(); + + if ( newShortcut != YShortcut::None ) + { + char findme[] = { (char)tolower( newShortcut ), (char)toupper( newShortcut ), 0 }; + std::string::size_type pos = str.find_first_of( findme ); + + if ( pos == std::string::npos ) + { + yuiError() << "Can't find '<< " << newShortcut + << "' in item " + << " \"" << cleanShortcutString() << "\"" + << std::endl; + + return; + } + + str.insert( pos, + std::string( 1, shortcutMarker() ) ); // equivalent to 'std::string( "& " )' + } + + _item->setLabel( str ); + + // Notify the parent widget + widget()->setShortcutString( widget()->shortcutString() ); + + _shortcutStringCached = false; + _cleanShortcutStringCached = false; + _shortcut = newShortcut; + +} diff --git a/src/YShortcut.h b/src/YShortcut.h new file mode 100644 index 0000000..319dfb6 --- /dev/null +++ b/src/YShortcut.h @@ -0,0 +1,271 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YShortcut.h + + Author: Stefan Hundhammer + +/-*/ + + +#ifndef YShortcut_h +#define YShortcut_h + +#include "YWidget.h" +#include +#include + +class YItem; + + +/** + * Helper class for shortcut management: + * This class holds data about the shortcut for one single widget. + **/ +class YShortcut +{ +public: + /** + * Constructor + **/ + YShortcut( YWidget *shortcut_widget ); + + /** + * Destructor + **/ + virtual ~YShortcut(); + + /** + * Marker for "no shortcut" + **/ + enum { None = 0 }; + + /** + * Returns the YWidget this shortcut data belong to. + **/ + YWidget * widget() const { return _widget; } + + /** + * Returns the textual representation of the widget class of the widget + * this shortcut data belongs to. + **/ + const char * widgetClass() const { return widget()->widgetClass(); } + + /** + * Returns 'true' if the widget that is associated with this shortcut is a + * button (derived from YPushButton). + **/ + bool isButton() const { return _isButton; } + + /** + * Returns 'true' if the widget that is associated with this shortcut is a + * wizard button (one of the navigation buttons of a wizard). + **/ + bool isWizardButton() const { return _isWizardButton; } + + /** + * Returns the complete shortcut string (which may or may not contain "&"), + * i.e. the value of the widget's shortcut property. For PushButtons, this + * is the label on the button ( e.g., "&Details..." ), for other widgets + * usually the caption above it. + * + * This value is chached, i.e. this isn't a too expensive operation. + **/ + std::string shortcutString(); + + /** + * Returns the shortcut string ( from the widget's shortcut property ) + * without any "&" markers. + **/ + std::string cleanShortcutString(); + + /** + * Static version of the above for general use: + * Returns the specified string without any "&" markers. + **/ + static std::string cleanShortcutString( std::string shortcutString ); + + /** + * The preferred shortcut character, i.e. the character that had been + * preceded by "&" before checking / resolving conflicts began. + **/ + char preferred(); + + /** + * The actual shortcut character. + * + * This may be different from preferred() if it is overridden. + **/ + char shortcut(); + + /** + * Set (override) the shortcut character. + **/ + virtual void setShortcut( char newShortcut ); + + /** + * Clear the shortcut: Override the shortcut character with nothing. + * This may happen if a conflict cannot be resolved. + **/ + void clearShortcut(); + + /** + * Query the internal 'conflict' marker. This class doesn't care about that + * flag, it just stores it for the convenience of higher-level classes. + **/ + bool conflict() { return _conflict; } + + /** + * Set or unset the internal 'conflict' marker. + **/ + void setConflict( bool newConflictState = true ) { _conflict = newConflictState; } + + /** + * Obtain the number of distinct valid shortcut characters in the shortcut + * string, i.e. how many different shortcuts that widget could get. + **/ + int distinctShortcutChars(); + + /** + * Return true if this shortcut contains any character that would be valid + * as a shortcut character. + **/ + bool hasValidShortcutChar(); + + /** + * Static function: Returns the character used for marking keyboard + * shortcuts. + **/ + static char shortcutMarker() { return '&'; } + + /** + * Static function: Find the next occurrence of the shortcut marker ('&') + * in a string, beginning at starting position start_pos. + * + * Returns string::npos if not found or the position of the shortcut marker + * (not the shortcut character!) if found. + **/ + static std::string::size_type findShortcutPos( const std::string & str, std::string::size_type start_pos = 0 ); + + /** + * Static function: Find the next shortcut marker in a string, beginning at + * starting position start_pos. + * + * Returns the shortcut character or 0 if none found. + **/ + static char findShortcut( const std::string & str, std::string::size_type start_pos = 0 ); + + /** + * Returns 'true' if 'c' is a valid shortcut character, i.e. [a-zA-Z0-9], + * 'false' otherwise. + **/ + static bool isValid( char c ); + + /** + * Return the normalized version of shortcut character 'c', i.e. a + * lowercase letter or a digit [a-z0-9]. Returns 0 if 'c' is invalid. + **/ + static char normalized( char c ); + + /** + * Obtain a widget's shortcut property - the string that contains "&" to + * designate a shortcut. + **/ + static std::string getShortcutString( const YWidget * widget ); + + +protected: + + /** + * Obtain the the shortcut property of this shortcut's widget - the string + * that contains "&" to designate a shortcut. + **/ + virtual std::string getShortcutString(); + + + // Data members + + YWidget * _widget; + std::string _shortcutString; + bool _shortcutStringCached; + + std::string _cleanShortcutString; + bool _cleanShortcutStringCached; + + int _preferred; // int to enable initializing with invalid char (-1) + int _shortcut; // int to enable initializing with invalid char (-1) + + bool _conflict; + bool _isButton; + bool _isWizardButton; + int _distinctShortcutChars; +}; + + + +/** + * Special case for widgets that can have multiple shortcuts based on items + * (like YDumbTab) + **/ +class YItemShortcut: public YShortcut +{ +public: + /** + * Constructor. + **/ + YItemShortcut( YWidget * widget, YItem * item ) + : YShortcut( widget ) + , _item( item ) + {} + + /** + * Destructor. + **/ + virtual ~YItemShortcut() {} + + /** + * Return the associated item. + **/ + YItem * item() const { return _item; } + + /** + * Set (override) the shortcut character. + * In this subclass, it will change the internally stored item. + **/ + virtual void setShortcut( char newShortcut ); + +protected: + + /** + * Obtain the the shortcut property of this shortcut's widget - the string + * that contains "&" to designate a shortcut. + **/ + virtual std::string getShortcutString(); + + +private: + + YItem * _item; +}; + + +typedef std::vector YShortcutList; +typedef YShortcutList::iterator YShortcutListIterator; + + +#endif // YShortcut_h diff --git a/src/YShortcutManager.cc b/src/YShortcutManager.cc new file mode 100644 index 0000000..a39187b --- /dev/null +++ b/src/YShortcutManager.cc @@ -0,0 +1,410 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YShortcutManager.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui-shortcuts" +#include "YUILog.h" + +#include "YShortcutManager.h" +#include "YDialog.h" +#include "YDumbTab.h" + + +// Threshold of widgets with valid shortcut characters below which no shortcut +// check is performed at all. This might regularly occur for languages that +// primarily use non-ASCII characters (Russian, Greek, Chinese, Japanese, +// Korean). +#define MIN_VALID_PERCENT 50 + +// Return the number of elements of an array of any type +#define DIM( ARRAY ) ( (int) ( sizeof( ARRAY)/( sizeof( ARRAY[0] ) ) ) ) + + +YShortcutManager::YShortcutManager( YDialog *dialog ) + : _dialog( dialog ) + , _conflictCount( 0 ) + , _didCheck( false ) +{ + YUI_CHECK_PTR( _dialog ); +} + + +YShortcutManager::~YShortcutManager() +{ + clearShortcutList(); +} + + +void +YShortcutManager::checkShortcuts( bool autoResolve ) +{ + yuiDebug() << "Checking keyboard shortcuts" << std::endl; + + clearShortcutList(); + findShortcutWidgets( _dialog->childrenBegin(), _dialog->childrenEnd() ); + + int validCount = 0; + + for ( unsigned i=0; i < _shortcutList.size(); i++ ) + { + if ( _shortcutList[i]->hasValidShortcutChar() ) + ++validCount; + } + + int validPercent = _shortcutList.size() > 0 ? + ( 100 * validCount ) / _shortcutList.size() : 0; + + if ( validPercent < MIN_VALID_PERCENT ) + { + // No check at all if there are not enough widgets with valid shortcut + // characters ([A-Za-z0-9]). This might regularly occur for languages + // that primarily use non-ASCII characters (Russian, Greek, Chinese, + // Japanese, Korean). + + yuiWarning() << "Not enough widgets with valid shortcut characters - no check" << std::endl; + yuiDebug() << "Found " << validCount << " widgets with valid shortcut characters" << std::endl; + return; + } + + + // Initialize wanted character counters + for ( int i=0; i < DIM( _wanted ); i++ ) + _wanted[i] = 0; + + // Initialize used character flags + for ( int i=0; i < DIM( _wanted ); i++ ) + _used[i] = false; + + // Count wanted shortcuts + for ( unsigned i=0; i < _shortcutList.size(); i++ ) + _wanted[ (int) _shortcutList[i]->preferred() ]++; + + + // Report errors + + _conflictCount = 0; + + for ( unsigned i=0; i < _shortcutList.size(); i++ ) + { + YShortcut *shortcut = _shortcutList[i]; + + if ( YShortcut::isValid( shortcut->preferred() ) ) + { + if ( _wanted[ (int) shortcut->preferred() ] > 1 ) // shortcut char used more than once + { + shortcut->setConflict(); + _conflictCount++; + + yuiDebug() << "Shortcut conflict: '" << shortcut->preferred() + << "' used for " << shortcut->widget() + << std::endl; + } + } + else // No or invalid shortcut + { + if ( shortcut->cleanShortcutString().length() > 0 ) + { + shortcut->setConflict(); + _conflictCount++; + + if ( ! shortcut->widget()->autoShortcut() ) + { + yuiDebug() << "No valid shortcut for " << shortcut->widget() << std::endl; + } + } + } + + if ( ! shortcut->conflict() ) + { + _used[ (int) shortcut->preferred() ] = true; + } + } + + _didCheck = true; + + if ( _conflictCount > 0 ) + { + if ( autoResolve ) + { + resolveAllConflicts(); + } + } + else + { + yuiDebug() << "No shortcut conflicts" << std::endl; + } +} + + +void +YShortcutManager::resolveAllConflicts() +{ + yuiDebug() << "Resolving shortcut conflicts" << std::endl; + + if ( ! _didCheck ) + { + yuiError() << "Call checkShortcuts() first!" << std::endl; + return; + } + + + // Make a list of all shortcuts with conflicts + + YShortcutList conflictList; + _conflictCount = 0; + + for ( YShortcutListIterator it = _shortcutList.begin(); + it != _shortcutList.end(); + ++it ) + { + if ( ( *it )->conflict() ) + { + conflictList.push_back( *it ); + _conflictCount++; + } + } + + + // Resolve each conflict + + while ( ! conflictList.empty() ) + { + // + // Pick a conflict widget to resolve. + // + + // Wizard buttons have priority - check any of them first. + int prioIndex = findShortestWizardButton( conflictList ); + + if ( prioIndex < 0 ) + prioIndex = findShortestWidget( conflictList); // Find the shortest widget. Buttons have priority. + + + // Pick a new shortcut for this widget. + + YShortcut * shortcut = conflictList[ prioIndex ]; + resolveConflict( shortcut ); + + if ( shortcut->conflict() ) + { + yuiWarning() << "Couldn't resolve shortcut conflict for " << shortcut->widget() << std::endl; + } + + + // Mark this particular conflict as resolved. + + conflictList.erase( conflictList.begin() + prioIndex ); + } + + if ( _conflictCount > 0 ) + { + yuiDebug() << _conflictCount << " shortcut conflict(s) left" << std::endl; + } +} + + + +void +YShortcutManager::resolveConflict( YShortcut * shortcut ) +{ + // yuiDebug() << "Picking shortcut for " << shortcut->widget() << std::endl; + + char candidate = shortcut->preferred(); // This is always normalized, no need to normalize again. + + if ( ! YShortcut::isValid( candidate ) // Can't use this character - pick another one. + || _used[ (int) candidate ] ) + { + candidate = 0; // Restart from scratch - forget the preferred character. + std::string str = shortcut->cleanShortcutString(); + + for ( std::string::size_type pos = 0; pos < str.length(); pos++ ) // Search all the shortcut string. + { + char c = YShortcut::normalized( str[ pos ] ); + // yuiDebug() << "Checking '" << c << "'" << std::endl; + + if ( YShortcut::isValid(c) && ! _used[ (int) c ] ) // Could we use this character? + { + if ( _wanted[ (int) c ] < _wanted[ (int) candidate ] // Is this a better choice than what we already have - + || ! YShortcut::isValid( candidate ) ) // or don't we have anything yet? + { + candidate = c; // Use this one. + // yuiDebug() << "Picking '" << c << "'" << std::endl; + + if ( _wanted[ (int) c ] == 0 ) // It doesn't get any better than this: + break; // Nobody wants this shortcut anyway. + } + } + } + } + + if ( YShortcut::isValid( candidate ) ) + { + if ( candidate != shortcut->preferred() ) + { + if ( shortcut->widget()->autoShortcut() ) + { + yuiDebug() << "Automatically assigning shortcut '" << candidate + << "' to " << shortcut->widgetClass() << "(`opt(`autoShortcut ), \"" + << shortcut->cleanShortcutString() << "\" )" + << std::endl; + } + else + { + yuiDebug() << "Reassigning shortcut '" << candidate + << "' to " << shortcut->widget() + << std::endl; + } + shortcut->setShortcut( candidate ); + } + else + { + yuiDebug() << "Keeping preferred shortcut '" << candidate + << "' for " << shortcut->widget() + << std::endl; + } + + _used[ (int) candidate ] = true; + shortcut->setConflict( false ); + } + else // No unique shortcut found + { + yuiWarning() << "Couldn't resolve shortcut conflict for " + << shortcut->widget() + << " - assigning no shortcut" + << std::endl; + + shortcut->clearShortcut(); + shortcut->setConflict( false ); + } + + _conflictCount--; +} + + + +int +YShortcutManager::findShortestWizardButton( const YShortcutList & conflictList ) +{ + int shortestIndex = -1; + int shortestLen = -1; + + for ( unsigned i=1; i < conflictList.size(); i++ ) + { + if ( conflictList[i]->isWizardButton() ) + { + if ( shortestLen < 0 || + conflictList[i]->distinctShortcutChars() < shortestLen ) + { + shortestIndex = i; + shortestLen = conflictList[i]->distinctShortcutChars(); + } + + } + } + + return shortestIndex; +} + + + +unsigned +YShortcutManager::findShortestWidget( const YShortcutList & conflictList ) +{ + unsigned shortestIndex = 0; + int shortestLen = conflictList[ shortestIndex ]->distinctShortcutChars(); + + for ( unsigned i=1; i < conflictList.size(); i++ ) + { + int currentLen = conflictList[i]->distinctShortcutChars(); + + if ( currentLen < shortestLen ) + { + // Found an even shorter one + + shortestIndex = i; + shortestLen = currentLen; + } + else if ( currentLen == shortestLen ) + { + if ( conflictList[i]->isButton() && + ! conflictList[ shortestIndex ]->isButton() ) + { + // Prefer a button over another widget with the same length + + shortestIndex = i; + shortestLen = currentLen; + } + } + } + + return shortestIndex; +} + + + +void +YShortcutManager::clearShortcutList() +{ + for ( unsigned i=0; i < _shortcutList.size(); i++ ) + { + delete _shortcutList[i]; + } + + _shortcutList.clear(); +} + + +void +YShortcutManager::findShortcutWidgets( YWidgetListConstIterator begin, + YWidgetListConstIterator end ) +{ + for ( YWidgetListConstIterator it = begin; it != end; ++it ) + { + YWidget * widget = *it; + + YDumbTab * dumbTab = dynamic_cast (widget); + + if ( dumbTab ) + { + for ( YItemConstIterator it = dumbTab->itemsBegin(); + it != dumbTab->itemsEnd(); + ++it ) + { + YItemShortcut * shortcut = new YItemShortcut( dumbTab, *it ); + _shortcutList.push_back( shortcut ); + } + } + else if ( ! widget->shortcutString().empty() ) + { + YShortcut * shortcut = new YShortcut( *it ); + _shortcutList.push_back( shortcut ); + } + + if ( widget->hasChildren() ) + { + findShortcutWidgets( widget->childrenBegin(), + widget->childrenEnd() ); + } + } +} diff --git a/src/YShortcutManager.h b/src/YShortcutManager.h new file mode 100644 index 0000000..e988f7a --- /dev/null +++ b/src/YShortcutManager.h @@ -0,0 +1,175 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YShortcutManager.h + + Author: Stefan Hundhammer + +/-*/ + + +#ifndef YShortcutManager_h +#define YShortcutManager_h + +#include "YWidget.h" +#include "YShortcut.h" + +class YDialog; + +/** + * Helper class to manage keyboard shortcuts within one dialog and resolve + * keyboard shortcut conflicts. + **/ +class YShortcutManager +{ +public: + /** + * Constructor. + **/ + YShortcutManager( YDialog *dialog ); + + /** + * Destructor + **/ + virtual ~YShortcutManager(); + + /** + * Check the keyboard shortcuts of all children of this dialog + * (not for sub-dialogs!). + * + * Call resolveAllConflicts() if 'autoResolve' is 'true'. + **/ + void checkShortcuts( bool autoResolve = true ); + + /** + * Returns the number of shortcut conflicts. + * Valid only after checkShortcuts() or resolveAllConflicts(). + **/ + int conflictCount() { return _conflictCount; } + + /** + * Resolve shortcut conflicts. Requires checkShortcuts() to be called first. + * + * Note: This may or may not work. There is no general solution to that + * problem. This method tries its best, but you may end up with widgets + * that don't have any ( more ) shortcut. + * + * Why? Just picture the following ( admittedly pathologic ) situation: + * + * [& OK] + * [& OK] + * [& OK] + * + * This will result in something like this: + * + * [& OK] + * [O& K] + * [OK] + * + * I.e. the first OK button will retain its preferred shortcut ( 'O' ), the + * second OK button's shortcut will be reassigned to 'K' and the third + * won't get any - there are simply not enough eligible shortcut + * characters. + * + * This may even fail in much less pathological situations. This example is + * only supposed to give you a general idea why not to blindly rely on + * automatic shortcut resolving. + * + * It's always best to resolve conflicts manually. This will generally + * result in much better shortcuts: Easier to memorize, less chance of + * picking characters that cannot really do a good job showing their + * shortcut like very narrow characters ( .e.g., 'i' ) or descender + * characters ( e.g., 'g', 'p', 'q' - imagine those underlined! ). + **/ + void resolveAllConflicts(); + + /** + * Returns the dialog this shortcut manager works on. + **/ + YDialog *dialog() { return _dialog; } + +protected: + + /** + * Delete all members of the internal shortcut list, then empty the list. + **/ + void clearShortcutList(); + + /** + * Recursively search all widgets between iterators 'begin' and 'end' (not + * those of any sub-dialogs!) for child widgets that could accept a + * keyboard shortcut and add these to _shortcutList. + **/ + void findShortcutWidgets( YWidgetListConstIterator begin, + YWidgetListConstIterator end ); + + /** + * Pick a new shortcut character for 'shortcut' - one that isn't marked as + * used in the '_used' array. Unset the conflict marker if that succeeded. + **/ + void resolveConflict( YShortcut * shortcut ); + + /** + * Find the shortest wizard button in 'conflictList', if there is any. + * Returns the index of that shortest wizard button or -1 if there is none. + **/ + int findShortestWizardButton( const YShortcutList & conflictList ); + + /** + * Find the shortest widget in 'conflictList'. Buttons get priority if they + * have the same number of eligible shortcut characters as another widget. + * + * Returns the index of the shortest widget. + **/ + unsigned findShortestWidget( const YShortcutList & conflictList ); + + /** + * The dialog this shortcut manager works on. + **/ + YDialog *_dialog; + + /** + * List of all the shortcuts in this dialog. + **/ + YShortcutList _shortcutList; + + /** + * Counters for wanted shortcut characters. + **/ + int _wanted[ sizeof( char ) << 8 ]; + + + /** + * Flags for used shortcut characters. + **/ + bool _used[ sizeof( char ) << 8 ]; + + + /** + * Counter for shortcut conflicts + **/ + int _conflictCount; + + +private: + + bool _didCheck; +}; + + +#endif // YShortcutManager_h diff --git a/src/YSimpleEventHandler.cc b/src/YSimpleEventHandler.cc new file mode 100644 index 0000000..e0cbd1e --- /dev/null +++ b/src/YSimpleEventHandler.cc @@ -0,0 +1,176 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEvent.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui-events" +#include "YUILog.h" + +#include "YEvent.h" +#include "YSimpleEventHandler.h" + + + +#define VERBOSE_EVENTS 0 +#define VERBOSE_BLOCK 0 + + +YSimpleEventHandler::YSimpleEventHandler() +{ + _pendingEvent = 0; + _eventsBlocked = false; +} + + +YSimpleEventHandler::~YSimpleEventHandler() +{ + clear(); +} + + +void YSimpleEventHandler::clear() +{ + if ( _pendingEvent ) + { +#if VERBOSE_EVENTS + yuiDebug() << "Clearing pending event: " << _pendingEvent << std::endl; +#endif + deleteEvent( _pendingEvent ); + } +} + + +YEvent * YSimpleEventHandler::consumePendingEvent() +{ + YEvent * event = _pendingEvent; + _pendingEvent = 0; + +#if VERBOSE_EVENTS + yuiDebug() << "Consuming " << event << std::endl; +#endif + + return event; +} + + +void YSimpleEventHandler::sendEvent( YEvent * event ) +{ + if ( ! event ) + { + yuiError() << "Ignoring NULL event" << std::endl; + return; + } + + if ( eventsBlocked() ) + { +#if VERBOSE_BLOCK + yuiDebug() << "Blocking " << event << std::endl; +#endif + // Avoid memory leak: The event handler assumes ownership of the newly + // created event, so we have to clean it up here. + deleteEvent( event ); + + return; + } + + if ( _pendingEvent ) + { + /** + * This simple event handler keeps track of only the latest user event. + * If there is more than one, older events are automatically discarded. + * Since Events are created on the heap with the "new" operator, + * discarded events need to be deleted. + * + * Events that are not discarded are deleted later (after they are + * processed) by the generic UI. + **/ + + deleteEvent( _pendingEvent ); + } + +#if VERBOSE_EVENTS + yuiDebug() << "New pending event: " << event << std::endl; +#endif + + _pendingEvent = event; +} + + +bool +YSimpleEventHandler::eventPendingFor( YWidget * widget ) const +{ + YWidgetEvent * event = dynamic_cast (_pendingEvent); + + if ( ! event ) + return false; + + return event->widget() == widget; +} + + +void YSimpleEventHandler::deletePendingEventsFor( YWidget * widget ) +{ + if ( ! _pendingEvent ) + return; + + YWidgetEvent * event = dynamic_cast (_pendingEvent); + + if ( event && event->widget() == widget && event->isValid() ) + { + yuiDebug() << "Deleting " << _pendingEvent << std::endl; + deleteEvent( _pendingEvent ); + } +} + + +void YSimpleEventHandler::blockEvents( bool block ) +{ +#if VERBOSE_BLOCK + if ( block ) yuiDebug() << "Blocking events" << std::endl; + else yuiDebug() << "Unblocking events" << std::endl; +#endif + + _eventsBlocked = block; +} + + +void YSimpleEventHandler::deleteEvent( YEvent * event ) +{ + if ( event == _pendingEvent ) + _pendingEvent = 0; + + if ( event ) + { + if ( event->isValid() ) + { +#if VERBOSE_EVENTS + yuiDebug() << "Deleting " << event << std::endl; +#endif + delete event; + } + else + { + yuiError() << "Attempt to delete invalid event " << event << std::endl; + } + } +} diff --git a/src/YSimpleEventHandler.h b/src/YSimpleEventHandler.h new file mode 100644 index 0000000..e8018b7 --- /dev/null +++ b/src/YSimpleEventHandler.h @@ -0,0 +1,141 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSimpleEventHandler.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSimpleEventHandler_h +#define YSimpleEventHandler_h + + +class YEvent; +class YWidget; + + +/** + * Simple event handler suitable for most UIs. + * + * This event handler keeps track of one single event that gets overwritten + * when a new one arrives. + **/ +class YSimpleEventHandler +{ +public: + + /** + * Constructor. + **/ + YSimpleEventHandler(); + + /** + * Destructor. + * + * If there is a pending event, it is deleted here. + **/ + virtual ~YSimpleEventHandler(); + + /** + * Widget event handlers call this when an event occured that + * should be the answer to a UserInput() / PollInput() (etc.) call. + * + * The UI assumes ownership of the event object that 'event' points to, so + * the event MUST be created with new(). The UI is to take care to delete + * the event after it has been processed. + * + * If events are blocked (see blockEvents() ), the event sent with this + * function will be ignored (but safely deleted - no memory leak). + * + * It is an error to pass 0 for 'event'. + **/ + void sendEvent( YEvent * event_disown ); + + /** + * Returns 'true' if there is any event pending for the specified widget. + **/ + bool eventPendingFor( YWidget * widget ) const; + + /** + * Returns the last event that isn't processed yet or 0 if there is none. + * + * This event handler keeps track of only one single (the last one) event. + **/ + YEvent * pendingEvent() const { return _pendingEvent; } + + /** + * Consumes the pending event. Sets the internal pending event to 0. + * Does NOT delete the internal consuming event. + * + * The caller assumes ownership of the object this pending event points + * to. In particular, he has to take care to delete that object when he is + * done processing it. + * + * Returns the pending event or 0 if there is none. + **/ + YEvent * consumePendingEvent(); + + /** + * Delete any pending events for the specified widget. This is useful + * mostly if the widget is about to be destroyed. + **/ + void deletePendingEventsFor( YWidget * widget ); + + /** + * Clears any pending event (deletes the corresponding object). + **/ + void clear(); + + /** + * Block (or unblock) events. If events are blocked, any event sent with + * sendEvent() from now on is ignored (and will get lost) until events are + * unblocked again. + **/ + void blockEvents( bool block = true ); + + /** + * Unblock events previously blocked. This is just an alias for + * blockEvents( false) for better readability. + **/ + void unblockEvents() { blockEvents( false ); } + + /** + * Returns 'true' if events are currently blocked. + **/ + bool eventsBlocked() const { return _eventsBlocked; } + + /** + * Delete an event. Don't call this from the outside; this is public only + * because of limitations of C++ . + **/ + void deleteEvent( YEvent * event ); + + +protected: + + // Data members + + YEvent * _pendingEvent; + bool _eventsBlocked; +}; + + + + +#endif // YSimpleEventHandler_h diff --git a/src/YSimpleInputField.cc b/src/YSimpleInputField.cc new file mode 100644 index 0000000..d0b6f2a --- /dev/null +++ b/src/YSimpleInputField.cc @@ -0,0 +1,122 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSimpleInputField.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YSimpleInputField.h" + + +struct YSimpleInputFieldPrivate +{ + YSimpleInputFieldPrivate( const std::string & label ) + : label( label ) + {} + + std::string label; +}; + + + + +YSimpleInputField::YSimpleInputField( YWidget * parent, const std::string & label ) + : YWidget( parent ) + , priv( new YSimpleInputFieldPrivate( label ) ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, false ); + setDefaultStretchable( YD_VERT, false ); +} + + +YSimpleInputField::~YSimpleInputField() +{ + // NOP +} + + +std::string YSimpleInputField::label() const +{ + return priv->label; +} + + +void YSimpleInputField::setLabel( const std::string & label ) +{ + priv->label = label; +} + + + +const YPropertySet & +YSimpleInputField::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string Value the text the user entered + * @property std::string Label caption above the input field + */ + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YSimpleInputField::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) setValue( val.stringVal() ); + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YSimpleInputField::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( value() ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YSimpleInputField.h b/src/YSimpleInputField.h new file mode 100644 index 0000000..6d926d4 --- /dev/null +++ b/src/YSimpleInputField.h @@ -0,0 +1,137 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSimpleInputField.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSimpleInputField_h +#define YSimpleInputField_h + +#include "YWidget.h" + +class YSimpleInputFieldPrivate; + + +/** + * Abstract base class for simple input fields with a label above the field and + * a text value. + **/ +class YSimpleInputField : public YWidget +{ +protected: + /** + * Constructor. + **/ + YSimpleInputField( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YSimpleInputField(); + + /** + * Get the current value (the text entered by the user or set from the + * outside) of this input field. + * + * Derived classes are required to implement this. + **/ + virtual std::string value() = 0; + + /** + * Set the current value (the text entered by the user or set from the + * outside) of this input field. + * + * Derived classes are required to implement this. + **/ + virtual void setValue( const std::string & text ) = 0; + + /** + * Get the label (the caption above the input field). + **/ + std::string label() const; + + /** + * Set the label (the caption above the input field). + * + * Derived classes are free to reimplement this, but they should call this + * base class method at the end of the overloaded function. + **/ + virtual void setLabel( const std::string & label ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Get the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual std::string shortcutString() const { return label(); } + + /** + * Set the string of this widget that holds the keyboard shortcut. + * + * Reimplemented from YWidget. + **/ + virtual void setShortcutString( const std::string & str ) + { setLabel( str ); } + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_Value; } + + +private: + + ImplPtr priv; +}; + + +#endif // YSimpleInputField_h diff --git a/src/YSingleChildContainerWidget.cc b/src/YSingleChildContainerWidget.cc new file mode 100644 index 0000000..82a02cf --- /dev/null +++ b/src/YSingleChildContainerWidget.cc @@ -0,0 +1,74 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSingleChildContainerWidget.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YSingleChildContainerWidget.h" + + +YSingleChildContainerWidget::YSingleChildContainerWidget( YWidget * parent ) + : YWidget( parent ) +{ + setChildrenManager( new YSingleWidgetChildManager( this ) ); +} + + +YSingleChildContainerWidget::~YSingleChildContainerWidget() +{ + // NOP +} + + +int YSingleChildContainerWidget::preferredWidth() +{ + if ( hasChildren() ) + return firstChild()->preferredWidth(); + else + return 0; +} + + +int YSingleChildContainerWidget::preferredHeight() +{ + if ( hasChildren() ) + return firstChild()->preferredHeight(); + else + return 0; +} + + +void YSingleChildContainerWidget::setSize( int width, int height ) +{ + if ( hasChildren() ) + firstChild()->setSize( width , height ); +} + + +bool +YSingleChildContainerWidget::stretchable( YUIDimension dim ) const +{ + if ( hasChildren() ) + return firstChild()->stretchable( dim ); + else + return YWidget::stretchable( dim ); +} diff --git a/src/YSingleChildContainerWidget.h b/src/YSingleChildContainerWidget.h new file mode 100644 index 0000000..a28c805 --- /dev/null +++ b/src/YSingleChildContainerWidget.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSingleChildContainerWidget.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSingleChildContainerWidget_h +#define YSingleChildContainerWidget_h + +#include "YWidget.h" + + +/** + * Container widget class that manages one child. + **/ +class YSingleChildContainerWidget: public YWidget +{ +protected: + /** + * Constructor. + **/ + YSingleChildContainerWidget( YWidget * parent ); + +public: + /** + * Destructor. + **/ + virtual ~YSingleChildContainerWidget(); + + /** + * Preferred width of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredWidth(); + + /** + * Preferred height of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredHeight(); + + /** + * Set the new size of the widget. + * In this case, the size of the single child is set. + * + * Reimplemented from YWidget. + **/ + virtual void setSize( int newWidth, int newHeight ); + + /** + * Returns 'true' if this widget is stretchable in the specified dimension. + * In this case, the stretchability of the single child is returned. + * + * Reimplemented from YWidget. + **/ + virtual bool stretchable( YUIDimension dim ) const; +}; + + + +#endif // YSingleChildContainerWidget_h diff --git a/src/YSlider.cc b/src/YSlider.cc new file mode 100644 index 0000000..707d8df --- /dev/null +++ b/src/YSlider.cc @@ -0,0 +1,72 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSlider.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YSlider.h" + + +struct YSliderPrivate +{ + YSliderPrivate() + {} + + bool dummy; +}; + + + + +YSlider::YSlider( YWidget * parent, + const std::string & label, + int minValue, + int maxValue ) + : YIntField( parent, label, minValue, maxValue ) + , priv( new YSliderPrivate() ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setStretchable( YD_VERT, false ); +} + + +YSlider::~YSlider() +{ + // NOP +} + + +// +// Property documentation - all inherited from YIntField: +// + +/* + * @property integer Value the slider value + * @property integer MinValue the minimum value + * @property integer MaxValue the maximum value + * @property std::string Label caption above the slider + */ diff --git a/src/YSlider.h b/src/YSlider.h new file mode 100644 index 0000000..d29f6b8 --- /dev/null +++ b/src/YSlider.h @@ -0,0 +1,80 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSlider.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSlider_h +#define YSlider_h + +#include "YIntField.h" + +class YSliderPrivate; + + +/** + * Slider: Input widget for an integer value between a minimum and a maximum + * value. Very similar to IntField in semantics, but with a graphical slider + * that can be dragged to the desired value. It also contains an IntField to + * allow entering the value directly. + * + * Don't confuse this widget with ProgressBar: ProgressBar is output-only. + * + * + * This is an optional widget, i.e. not all UIs support it. + **/ +class YSlider : public YIntField +{ +protected: + /** + * Constructor. + * + * Create a Slider with 'label' as the caption, and the specified minimum + * and maximum values. + * + * Note that YWidgetFactory::createSlider() also has an 'initialValue' + * parameter that is not used here (because the current value is not stored + * in this base class, but in the derived class). + **/ + YSlider( YWidget * parent, + const std::string & label, + int minValue, + int maxValue ); + +public: + /** + * Destructor. + **/ + virtual ~YSlider(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YSlider"; } + +private: + + ImplPtr priv; +}; + + +#endif // YSlider_h diff --git a/src/YSpacing.cc b/src/YSpacing.cc new file mode 100644 index 0000000..61b8461 --- /dev/null +++ b/src/YSpacing.cc @@ -0,0 +1,109 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YEmpty.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include "YSpacing.h" +#include "YUI.h" +#include "YApplication.h" + + +struct YSpacingPrivate +{ + YSpacingPrivate( YUIDimension dim, int size ) + : dim( dim ) + , size( size ) + {} + + YUIDimension dim; + int size; +}; + + + + +YSpacing::YSpacing( YWidget * parent, YUIDimension dim, bool stretchable, YLayoutSize_t layoutUnits ) + : YWidget( parent ) + , priv( new YSpacingPrivate( dim, YUI::app()->deviceUnits( dim, layoutUnits ) ) ) +{ + YUI_CHECK_NEW( priv ); + setStretchable( dim, stretchable ); + setStretchable( dim == YD_HORIZ ? YD_VERT : YD_HORIZ, false ); +} + + +YSpacing::~YSpacing() +{ + // NOP +} + + +YUIDimension +YSpacing::dimension() const +{ + return priv->dim; +} + + +int YSpacing::size() const +{ + return priv->size; +} + + +int YSpacing::size( YUIDimension dim ) const +{ + if ( dim == priv->dim ) return priv->size; + else return 0; +} + + +int YSpacing::preferredWidth() +{ + if ( priv->dim == YD_HORIZ ) + return priv->size; + else + return 0; +} + + +int YSpacing::preferredHeight() +{ + if ( priv->dim == YD_VERT ) + return priv->size; + else + return 0; +} + + +const char * +YSpacing::widgetClass() const +{ + if ( priv->size > 0 ) + return ( priv->dim == YD_HORIZ ) ? "YHSpacing" : "YVSpacing"; + + if ( stretchable( YD_HORIZ ) ) return "YHStretch"; + if ( stretchable( YD_VERT ) ) return "YVStretch"; + + return "YSpacing"; +} diff --git a/src/YSpacing.h b/src/YSpacing.h new file mode 100644 index 0000000..e8aafd3 --- /dev/null +++ b/src/YSpacing.h @@ -0,0 +1,118 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSpacing.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSpacing_h +#define YSpacing_h + +#include "YWidget.h" +#include "ImplPtr.h" + +class YSpacingPrivate; + + +/** + * HSpacing, VSpacing, HStretch, VStretch + **/ +class YSpacing: public YWidget +{ +public: + + /** + * Constructor. + * + * A Spacing/Stretch widget works only in one dimension ('dim') at the same + * time. But it can be stretchable and have a size at the same time, in + * which case the specified size acts very much like a minimal size - but + * not exactly, since YLayoutBox will reduce Spacings first before other + * widgets have to be resized below their preferred size. + * + * 'layoutUnits' is specified in abstract UI units where a main window + * (800x600 pixels in the Qt UI) corresponds to a 80x25 window. + **/ + YSpacing( YWidget * parent, + YUIDimension dim, + bool stretchable = false, + YLayoutSize_t layoutUnits = 0.0 ); + + /** + * Destructor. + **/ + virtual ~YSpacing(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const; + + /** + * Return the primary dimension of this Spacing/Stretch, + * i.e. the dimension in which it uses space or stretches. + **/ + YUIDimension dimension() const; + + /** + * Return the size in the primary dimension. + * + * This is the device dependent size (pixels or character cells), not the + * abstract UI layout unit from the constructor. + **/ + int size() const; + + /** + * Return the size in the specified dimension. + * + * This is the device dependent size (pixels or character cells), not the + * abstract UI layout unit from the constructor. + **/ + int size( YUIDimension dim ) const; + + /** + * Preferred width of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredWidth(); + + /** + * Preferred height of the widget. + * + * Reimplemented from YWidget. + **/ + virtual int preferredHeight(); + + +private: + + ImplPtr priv; +}; + + +typedef YSpacing YVSpacing; +typedef YSpacing YHSpacing; +typedef YSpacing YHStretch; +typedef YSpacing YVStretch; + + +#endif // YSpacing_h diff --git a/src/YSquash.cc b/src/YSquash.cc new file mode 100644 index 0000000..90c630f --- /dev/null +++ b/src/YSquash.cc @@ -0,0 +1,86 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSquash.cc + + Author: Stefan Hundhammer + +/-*/ + +#include "YSquash.h" +#include "YBothDim.h" + + +struct YSquashPrivate +{ + /** + * Constructor. + **/ + YSquashPrivate( bool horSquash, bool vertSquash ) + { + squash.hor = horSquash; + squash.vert = vertSquash; + } + + YBothDim squash; +}; + + +YSquash::YSquash( YWidget * parent, bool horSquash, bool vertSquash ) + : YSingleChildContainerWidget( parent ) + , priv( new YSquashPrivate( horSquash, vertSquash ) ) +{ + YUI_CHECK_NEW( priv ); +} + + +YSquash::~YSquash() +{ + // NOP +} + + +bool YSquash::horSquash() const +{ + return priv->squash.hor; +} + + +bool YSquash::vertSquash() const +{ + return priv->squash.vert; +} + + +bool YSquash::stretchable( YUIDimension dim ) const +{ + if ( ! hasChildren() ) + return false; + + return ! priv->squash[ dim ] && firstChild()->stretchable( dim ); +} + + +const char * +YSquash::widgetClass() const +{ + if ( priv->squash.hor && priv->squash.vert ) return "YHVSquash"; + else if ( priv->squash.hor ) return "YHSquash"; + else if ( priv->squash.vert ) return "YVSquash"; + else return "YSquash_NoSquash"; +} diff --git a/src/YSquash.h b/src/YSquash.h new file mode 100644 index 0000000..4bd0fb6 --- /dev/null +++ b/src/YSquash.h @@ -0,0 +1,88 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YSquash.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YSquash_h +#define YSquash_h + +#include "YSingleChildContainerWidget.h" +#include "ImplPtr.h" + + +class YSquashPrivate; + +/** + * HSquash, VSquash HVSquash: reduce child to its preferred size. + * + * Squash is a widget that "squashes" its one child during layout, i.e., it + * reduces it in size down to its preferred size. It may squash vertically, + * horizontally or in both dimensions. + **/ +class YSquash : public YSingleChildContainerWidget +{ +protected: + /** + * Constructor. + * + * Squashes horizontally if 'horSquash' is 'true', + * vertically if 'vertSquash' is 'true'. + **/ + YSquash( YWidget * parent, bool horSquash, bool vertSquash ); + +public: + /** + * Destructor. + **/ + virtual ~YSquash(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const; + + /** + * Returns 'true' if this widget squashes horizontally. + **/ + bool horSquash() const; + + /** + * Returns 'true' if this widget squashes vertically. + **/ + bool vertSquash() const; + + + /** + * In a squashed dimension the widget NOT stretchable. + * In an unsquashed dimension the widget is stretchable if the + * child is stretchable. + **/ + bool stretchable( YUIDimension dim ) const; + +private: + + ImplPtr priv; +}; + + +#endif // YSquash_h diff --git a/src/YStringTree.cc b/src/YStringTree.cc new file mode 100644 index 0000000..107ad60 --- /dev/null +++ b/src/YStringTree.cc @@ -0,0 +1,216 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YStringTree.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include +#include "YStringTree.h" + + + + +YStringTree::YStringTree( const char * domain ) + : _root( 0 ) +{ + setTextdomain( domain ); + _root = new YStringTreeItem( YTransText( "" ) ); +} + + +YStringTree::~YStringTree() +{ + if ( _root ) + delete _root; +} + + +YStringTreeItem * +YStringTree::addBranch( const std::string & content, + char delimiter, + YStringTreeItem * parent ) +{ + YStringTreeItem * node = 0; + + if ( ! parent ) + parent = _root; + + if ( delimiter == 0 ) + { + // Simple case: No delimiter, simply create a new item for 'content' + // and insert it. + + node = new YStringTreeItem( YTransText( content, translate( content ) ), parent ); + } + else + { + // Split 'content' into substrings and insert each subitem + + std::string::size_type start = 0; + std::string::size_type end = 0; + + while ( start < content.length() ) + { + // Skip delimiters + + while ( start < content.length() && + content[ start ] == delimiter ) + { + start++; + } + + + // Search next delimiter + + end = start; + + while ( end < content.length() && + content[ end ] != delimiter ) + { + end++; + } + + + // Extract substring, if there is any + + if ( end > start ) + { + std::string path_component = content.substr( start, end - start ); + YTransText path_component_trans( path_component, translate( path_component ) ); + + // Check if an entry with this text already exists + node = findDirectChild( parent, path_component_trans); + + if ( ! node ) // No entry with this text yet? Create one. + node = new YStringTreeItem( path_component_trans, parent ); + + parent = node; + } + + start = end; + } + } + + return node; +} + + +std::string +YStringTree::translate( const std::string & orig ) +{ + std::string trans( dgettext( _textdomain.c_str(), orig.c_str() ) ); + + return trans; +} + + +std::string +YStringTree::completePath( const YStringTreeItem * item, + bool translated, + char delimiter, + bool startWithDelimiter ) +{ + std::string path; + + if ( item ) + { + path = translated ? item->value().trans() : item->value().orig(); + + while ( item->parent() && item->parent() != _root ) + { + std::string parentPath = translated ? + item->parent()->value().translation() : + item->parent()->value().orig(); + + path = parentPath + delimiter + path; + item = item->parent(); + } + + } + + if ( startWithDelimiter ) + path = delimiter + path; + + return path; +} + + +YTransText +YStringTree::path( const YStringTreeItem * item, + char delimiter, + bool startWithDelimiter ) +{ + if ( ! item ) + return YTransText( "", "" ); + + YTransText path = item->value(); + + while ( item->parent() && item->parent() != _root ) + { + path.setOrig ( item->parent()->value().orig() + delimiter + path.orig() ); + path.setTranslation( item->parent()->value().trans() + delimiter + path.trans() ); + + item = item->parent(); + } + + if ( startWithDelimiter ) + { + path.setOrig ( delimiter + path.orig() ); + path.setTranslation( delimiter + path.translation() ); + } + + return path; +} + + +void +YStringTree::logTree() +{ + printf( "Tree:\n" ); + logBranch( _root, "" ); + printf( " " ); +} + + +void +YStringTree::logBranch( YStringTreeItem * branch, std::string indentation ) +{ + if ( branch ) + { + printf( "%s%s (%s)\n", indentation.c_str(), + branch->value().translation().c_str(), + branch->value().orig().c_str() ); + + YStringTreeItem * child = branch->firstChild(); + indentation += " "; + + while ( child ) + { + logBranch( child, indentation ); + child = child->next(); + } + } + else + { + printf( "%s\n", indentation.c_str() ); + } +} diff --git a/src/YStringTree.h b/src/YStringTree.h new file mode 100644 index 0000000..48cb29d --- /dev/null +++ b/src/YStringTree.h @@ -0,0 +1,193 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YStringTree.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YStringTree_h +#define YStringTree_h + +#include +#include "YTransText.h" +#include "TreeItem.h" + + +typedef SortedTreeItem YStringTreeItem; + + + +/** + * Abstract base class for filter views with hierarchical filter + * criteria - e.g., RPM group tags, MIME types. + **/ +class YStringTree +{ +public: + + /** + * Constructor. + * + * 'textdomain' specifies the gettext textdomain to use to translate + * pathname components as new branches are added. + * + * NOTE: This will NOT change the gettext environment in any way - the tree + * uses dgettext() internally. The caller is responsible to bind that + * textdomain to a message catalog (bindtextdomain() etc.). + **/ + + YStringTree( const char * textdomain ); + + /** + * Destructor. + **/ + virtual ~YStringTree(); + + /** + * Add a unique new branch with text content 'content' to the tree, + * beginning at 'parent' (root if parent == 0). This content can be a path + * specification delimited with character 'delimiter' (if not 0), i.e. this + * method will split 'content' up into path components and insert tree + * items for each level as appropriate. Leading delimiters will be ignored. + * If 'delimiter' is 0, 'content' is not split but used 'as is'. Items are + * automatically sorted alphabetically. Pathname components are + * automatically translated using the textdomain specified in the + * constructor. + * + * Returns the tree node for this branch - either newly created or the + * existing one. + * + * + * Example: + * addBranch( "/usr/local/bin", '/' ) + * addBranch( "/usr/lib", '/' ) + * + * "usr" + * "lib" + * "local" + * "bin" + **/ + YStringTreeItem * addBranch( const std::string & content, + char delimiter = 0, + YStringTreeItem * parent = 0 ); + + + /** + * Construct a complete original path for the specified tree item. + * 'startWithDelimiter' specifies whether or not the complete path should + * start with the delimiter character. + **/ + std::string origPath( const YStringTreeItem * item, + char delimiter, + bool startWithDelimiter = true ) + { return completePath( item, false, delimiter, startWithDelimiter ); } + + + /** + * Construct a complete original path for the specified tree item. + * 'startWithDelimiter' specifies whether or not the complete path should + * start with the delimiter character. + **/ + std::string translatedPath( const YStringTreeItem * item, + char delimiter, + bool startWithDelimiter = true ) + { return completePath( item, true, delimiter, startWithDelimiter ); } + + + /** + * Construct a complete path (both original and translated) for the + * specified tree item. 'startWithDelimiter' specifies whether or not the + * complete path should start with the delimiter character. + * + * Note: origPath() or translatedPath() are much cheaper if only one + * version (original or translated) is required. + **/ + YTransText path( const YStringTreeItem *item, + char delimiter, + bool startWithDelimiter = true ); + + + /** + * Debugging - dump the tree into the log file. + **/ + void logTree(); + + + /** + * Returns the root of the filter view tree. + * Note: In most cases, the root item itself will not contain any useful + * information. Consider it the handle for the entire tree, not an actual + * data element. + **/ + YStringTreeItem * root() const { return _root; } + + + /** + * Returns the textdomain used internally for translation of pathname + * components. + **/ + const char * textdomain() const { return _textdomain.c_str(); } + + + /** + * Set the textdomain used internally for translation of pathname + * components. + * + * NOTE: This will NOT change the gettext environment in any way - the tree + * uses dgettext() internally. The caller is responsible to bind that + * textdomain to a message catalog (bindtextdomain() etc.). + **/ + void setTextdomain( const char * domain ) { _textdomain = domain; } + + /** + * Translate message 'orig' using the internal textdomain. Returns the + * translated text or the original if there is no translation. + **/ + std::string translate( const std::string & orig ); + + +protected: + + /** + * Construct a complete original or translated path for the specified tree + * item. 'startWithDelimiter' specifies whether or not the complete path + * should start with the delimiter character. + **/ + std::string completePath( const YStringTreeItem * item, + bool translated, + char delimiter, + bool startWithDelimiter ); + + /** + * Debugging - dump one branch of the tree into the log file. + **/ + void logBranch( YStringTreeItem * branch, std::string indentation ); + + + // Data members + + YStringTreeItem * _root; + std::string _textdomain; +}; + + + + +#endif // YStringTree_h diff --git a/src/YTable.cc b/src/YTable.cc new file mode 100644 index 0000000..9d30e05 --- /dev/null +++ b/src/YTable.cc @@ -0,0 +1,222 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTable.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YTable.h" + + +struct YTablePrivate +{ + YTablePrivate( YTableHeader * header ) + : header( header ) + , keepSorting( false ) + , immediateMode( false ) + { + } + + YTableHeader * header; + bool keepSorting; + bool immediateMode; +}; + + + + +YTable::YTable( YWidget * parent, YTableHeader * header, bool multiSelection ) + : YSelectionWidget( parent, + "", // label + ! multiSelection ) // enforceSingleSelection + , priv( new YTablePrivate( header ) ) +{ + YUI_CHECK_PTR( header ); + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YTable::~YTable() +{ + if ( priv->header ) + delete priv->header; +} + + +void +YTable::setTableHeader( YTableHeader * newHeader ) +{ + YUI_CHECK_PTR( newHeader ); + + if ( priv->header->columns() != newHeader->columns() ) + deleteAllItems(); + + delete priv->header; + priv->header = newHeader; +} + + +int +YTable::columns() const +{ + return priv->header->columns(); +} + + +bool +YTable::hasColumn( int column ) const +{ + return priv->header->hasColumn( column ); +} + + +std::string +YTable::header( int column ) const +{ + return priv->header->header( column ); +} + + +YAlignmentType +YTable::alignment( int column ) const +{ + return priv->header->alignment( column ); +} + + +bool +YTable::immediateMode() const +{ + return priv->immediateMode; +} + + +void +YTable::setImmediateMode( bool immediateMode ) +{ + priv->immediateMode = immediateMode; + + if ( immediateMode ) + setNotify( true ); +} + + +bool +YTable::keepSorting() const +{ + return priv->keepSorting; +} + + +void +YTable::setKeepSorting( bool keepSorting ) +{ + priv->keepSorting = keepSorting; +} + + +bool +YTable::hasMultiSelection() const +{ + return ! YSelectionWidget::enforceSingleSelection(); +} + + +const YPropertySet & +YTable::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property itemID Value The currently selected item + * @property itemID CurrentItem The currently selected item + * @property itemList Items All items + * @property itemList SelectedItems All currently selected items + * @property std::string Cell One cell (one column of one item) + * @property integer Cell (ChangeWidget only) One cell as integer + * @property `icon(...) Cell Icon for one one cell + * @property std::string Item Alias for Cell + * @property std::string Item QueryWidget only: Return one complete item + * @property std::string IconPath Base path for icons + * @property bool MultiSelection Flag: User can select multiple items (read-only) + */ + propSet.add( YProperty( YUIProperty_Value, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentItem, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_SelectedItems, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Cell, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Item, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_MultiSelection, YBoolProperty, true ) ); // read-only + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YTable::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) return false; // Needs special handling + else if ( propertyName == YUIProperty_CurrentItem ) return false; // Needs special handling + else if ( propertyName == YUIProperty_SelectedItems ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Cell ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Item ) return false; // Needs special handling + else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() ); + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YTable::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_CurrentItem ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_SelectedItems ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Cell ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Item ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YTable.h b/src/YTable.h new file mode 100644 index 0000000..6694f10 --- /dev/null +++ b/src/YTable.h @@ -0,0 +1,214 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTable.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YTable_h +#define YTable_h + +#include "YTypes.h" +#include "YSelectionWidget.h" +#include "YTableItem.h" +#include "YTableHeader.h" + +class YTablePrivate; + + + +/** + * Table: Selection list with multiple columns. The user can select exactly one + * row (with all its columns) from that list. Each cell (each column within + * each row) has a label text and an optional icon (*). + * + * This widget is similar to SelectionBox, but it has several columns for each + * item (each row). If just one column is desired, consider using SelectionBox + * instead. + * + * Note: This is not something like a spread sheet, and it doesn't pretend or + * want to be. Actions are performed on rows, not on individual cells (columns + * within one row). + * + * + * (*) Not all UIs (in particular not text-based UIs) support displaying icons, + * so an icon should never be an exclusive means to display any kind of + * information. + **/ +class YTable : public YSelectionWidget +{ +protected: + /** + * Constructor. + * + * 'header' describes the table's headers: Number of columns, column + * headings, and column alignment. The widget assumes ownership of this + * object and will delete it when appropriate. The header cannot be changed + * after creating the widget. + * + * 'multiSelection' indicates whether or not the user can select multiple + * items at the same time (e.g., with shift-click or ctrl-click). This can + * only be set in the constructor. + **/ + YTable( YWidget * parent, YTableHeader * header, bool multiSelection ); + +public: + + /** + * Destructor. + **/ + virtual ~YTable(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YTable"; } + + /** + * Return the number of columns of this table. + **/ + int columns() const; + + /** + * Return 'true' if this table has a column no. 'column' + * (counting from 0 on). + **/ + bool hasColumn( int column ) const; + + /** + * Return the header text for the specified column. + **/ + std::string header( int column ) const; + + /** + * Return the alignment for the specified column. + **/ + YAlignmentType alignment( int column ) const; + + /** + * Deliver even more events than with notify() set. + * + * With "notify" alone, a table widget sends an ActivatedEvent when the + * user double-clicks an item or presses the "space" key on it. It does + * not send an event when the user just sends another item. + * + * With "immediate", it also sends a SelectionChangedEvent when the user + * selects another item. "immediate" implicitly includes "notify". + **/ + bool immediateMode() const; + + /** + * Set immediateMode() on or off. + **/ + void setImmediateMode( bool immediateMode = true ); + + /** + * Return 'true' if the sort order is to be kept in item insertion order, + * i.e. if sorting the table by clicking on a column header should be + * disabled. + **/ + bool keepSorting() const; + + /** + * Switch between sorting by item insertion order (keepSorting: true) or + * allowing the user to sort by an arbitrary column (by clicking on the + * column header). + * + * Derived classes can overwrite this function, but they should call this + * base class function in the new implementation. + **/ + virtual void setKeepSorting( bool keepSorting ); + + /** + * Return 'true' if the user can select multiple items at the same time + * (e.g., with shift-click or ctrl-click). + **/ + bool hasMultiSelection() const; + + /** + * Notification that a cell (its text and/or its icon) was changed from the + * outside. Applications are required to call this whenever a table cell is + * changed after adding the corresponding table item (the row) to the table + * widget. + * + * Derived classes are required to implement this and update the display + * accordingly. + * + * Note that the position of this cell can be retrieved with cell->column() + * and cell->itemIndex(). + **/ + virtual void cellChanged( const YTableCell * cell ) = 0; + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_CurrentItem; } + + +protected: + + /** + * Exchange the previous table header with a new one. This will delete the + * old YTableHeader object. + * + * If the new header has a different number of columns than the old one, + * all items will implicitly be deleted. + **/ + void setTableHeader( YTableHeader * newHeader ); + +private: + + ImplPtr priv; +}; + + +#endif // YTable_h diff --git a/src/YTableHeader.cc b/src/YTableHeader.cc new file mode 100644 index 0000000..42bff5f --- /dev/null +++ b/src/YTableHeader.cc @@ -0,0 +1,100 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTableHeader.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YTableHeader.h" +#include "YUIException.h" + + + +struct YTableHeaderPrivate +{ + YTableHeaderPrivate() + {} + + std::vector headers; + std::vector alignments; +}; + + + + +YTableHeader::YTableHeader() + : priv( new YTableHeaderPrivate ) +{ + YUI_CHECK_NEW( priv ); +} + + +YTableHeader::~YTableHeader() +{ + // NOP +} + + +void +YTableHeader::addColumn( const std::string & header, YAlignmentType alignment ) +{ + priv->headers.push_back( header ); + priv->alignments.push_back( alignment ); +} + + +int +YTableHeader::columns() const +{ + return (int) priv->headers.size(); +} + + +bool +YTableHeader::hasColumn( int column ) const +{ + return column >= 0 && column < (int) priv->headers.size(); +} + + +std::string +YTableHeader::header( int column ) const +{ + if ( column >= 0 && column < (int) priv->headers.size() ) + return priv->headers[ column ]; + else + return ""; +} + + +YAlignmentType +YTableHeader::alignment( int column ) const +{ + if ( column >= 0 && column < (int) priv->alignments.size() ) + return priv->alignments[ column ]; + else + return YAlignBegin; +} diff --git a/src/YTableHeader.h b/src/YTableHeader.h new file mode 100644 index 0000000..70166c2 --- /dev/null +++ b/src/YTableHeader.h @@ -0,0 +1,90 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTableHeader.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YTableHeader_h +#define YTableHeader_h + +#include +#include "ImplPtr.h" +#include "YTypes.h" + + + +class YTableHeaderPrivate; + +/** + * Helper class for YTable for table column properties: + * + * - number of columns + * - header for each column + * - alignment for each column + **/ +class YTableHeader +{ +public: + /** + * Constructor. + **/ + YTableHeader(); + + /** + * Destructor. + **/ + virtual ~YTableHeader(); + + /** + * Add a column with the specified colum header text and alignment. + **/ + void addColumn( const std::string & header, + YAlignmentType alignment = YAlignBegin ); + + /** + * Return the number of columns. + **/ + int columns() const; + + /** + * Return 'true' if this table header has a column no. 'column' + * (counting from 0 on). + **/ + bool hasColumn( int column ) const; + + /** + * Return the header text for the specified column. + **/ + std::string header( int column ) const; + + /** + * Return the alignment for the specified column. + **/ + YAlignmentType alignment( int column ) const; + + +private: + + ImplPtr priv; +}; + + +#endif // YTableHeader_h diff --git a/src/YTableItem.cc b/src/YTableItem.cc new file mode 100644 index 0000000..f7dfbcf --- /dev/null +++ b/src/YTableItem.cc @@ -0,0 +1,181 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTableItem.cc + + Author: Stefan Hundhammer + +/-*/ + +#include "YTableItem.h" +#include "YUIException.h" + + +YTableItem::YTableItem() + : YItem( "" ) +{ + // NOP +} + + +YTableItem::YTableItem( const std::string & label_0, + const std::string & label_1, + const std::string & label_2, + const std::string & label_3, + const std::string & label_4, + const std::string & label_5, + const std::string & label_6, + const std::string & label_7, + const std::string & label_8, + const std::string & label_9 ) + : YItem( "" ) +{ + std::vector labels; + labels.reserve(10); // slight optimization + labels.push_back( label_0 ); + labels.push_back( label_1 ); + labels.push_back( label_2 ); + labels.push_back( label_3 ); + labels.push_back( label_4 ); + labels.push_back( label_5 ); + labels.push_back( label_6 ); + labels.push_back( label_7 ); + labels.push_back( label_8 ); + labels.push_back( label_9 ); + + // + // Find the last non-empty label + // + + unsigned lastLabel = labels.size() - 1; + + while ( labels[ lastLabel ].empty() && --lastLabel > 0 ) + {} + + // + // Create cells + // + + for ( unsigned i = 0; i <= lastLabel; ++i ) + { + addCell( labels[i] ); + } +} + + + +YTableItem::~YTableItem() +{ + deleteCells(); +} + + +void +YTableItem::deleteCells() +{ + YTableCellIterator it = cellsBegin(); + + while ( it != cellsEnd() ) + { + YTableCell * cell = *it; + ++it; + delete cell; + } + + _cells.clear(); +} + + +void +YTableItem::addCell( YTableCell * cell ) +{ + YUI_CHECK_PTR( cell ); + _cells.push_back( cell ); + + cell->reparent( this, _cells.size() - 1 ); +} + + +void +YTableItem::addCell( const std::string & label, const std::string & iconName ) +{ + YTableCell * cell = new YTableCell( label, iconName ); + YUI_CHECK_NEW( cell ); + + addCell( cell ); +} + + +bool +YTableItem::hasCell( int index ) const +{ + return index >= 0 && (unsigned) index < _cells.size(); +} + + +const YTableCell * +YTableItem::cell( int index ) const +{ + return hasCell( index ) ? + _cells[ index ] : 0; +} + + +YTableCell * +YTableItem::cell( int index ) +{ + return hasCell( index ) ? + _cells[ index ] : 0; +} + + +std::string +YTableItem::label( int index ) const +{ + return hasCell( index ) ? _cells[ index ]->label() : ""; +} + + +std::string +YTableItem::iconName( int index ) const +{ + return hasCell( index ) ? _cells[ index ]->iconName() : ""; +} + + +bool +YTableItem::hasIconName( int index ) const +{ + return hasCell( index ) ? _cells[ index ]->hasIconName() : false; +} + + + + + +void YTableCell::reparent( YTableItem * parent, int column ) +{ + YUI_CHECK_PTR( parent ); + + if ( _parent && _parent != parent && _column != column ) + YUI_THROW( YUIException( std::string( "Cannot reparent YTableCell \"" ) + + _label + + "to different parent." ) ); + _parent = parent; + _column = column; +} diff --git a/src/YTableItem.h b/src/YTableItem.h new file mode 100644 index 0000000..d443cc5 --- /dev/null +++ b/src/YTableItem.h @@ -0,0 +1,325 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTableItem.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YTableItem_h +#define YTableItem_h + +#include "YItem.h" + + +class YTableCell; + +// without "documenting" the file, typedefs will be dropped +//! @file + +//! Collection of pointers to YTableCell +typedef std::vector YTableCellCollection; +//! Mutable iterator over @ref YTableCellCollection +typedef YTableCellCollection::iterator YTableCellIterator; +//! Const iterator over @ref YTableCellCollection +typedef YTableCellCollection::const_iterator YTableCellConstIterator; + + +/** + * Item class for YTable items. Each YTableItem corresponds to one row in a + * YTable. + * + * A YTableItem might have any number of cells (columns within this row), + * including none. The YTable widget is free to ignore any excess cells if + * there are more than the YTable widget has columns. The YTable widget is to + * treat nonexistent cells like empty ones. + * + * Note that while YTable items and their cells can be manipulated through + * pointers, their visual representation on screen might be updated only upon + * calling certain methods of the YTable widget. See the YTable reference for + * details. + **/ +class YTableItem: public YItem +{ +public: + + /** + * Default constructor. Use addCell() to give it any content. + **/ + YTableItem(); + + /** + * Convenience constructor for table items without any icons. + * + * This will create up to 10 (0..9) cells. Empty cells for empty labels at + * the end of the labels are not created, but empty cells in between are. + * + * new YTableItem( "one", "two", "", "", "five" ); + * + * will create an item with 5 cells: + * + * cell[0] ==> "one" + * cell[1] ==> "two" + * cell[2] ==> "" + * cell[3] ==> "" + * cell[4] ==> "five" + **/ + YTableItem( const std::string & label_0, + const std::string & label_1 = std::string(), + const std::string & label_2 = std::string(), + const std::string & label_3 = std::string(), + const std::string & label_4 = std::string(), + const std::string & label_5 = std::string(), + const std::string & label_6 = std::string(), + const std::string & label_7 = std::string(), + const std::string & label_8 = std::string(), + const std::string & label_9 = std::string() ); + + /** + * Destructor. + * + * This will delete all cells. + **/ + virtual ~YTableItem(); + + /** + * Add a cell. This item will assume ownership over the cell and delete it + * when appropriate (when the table is destroyed or when table items are + * replaced), at which time the pointer will become invalid. + * + * Cells can still be changed after they (and the item they belong to) are + * added, but in that case, YTable::cellChanged() needs to be called to + * update the table display accordingly. + **/ + void addCell( YTableCell * cell_disown ); + + /** + * Create a new cell and add it (even if both 'label' and + * 'iconName' are empty). + **/ + void addCell( const std::string & label, const std::string & iconName = std::string() ); + + /** + * Delete all cells. + **/ + void deleteCells(); + + /** + * Return an iterator that points to the first cell of this item. + **/ + YTableCellIterator cellsBegin() { return _cells.begin(); } + YTableCellConstIterator cellsBegin() const { return _cells.begin(); } + + /** + * Return an iterator that points after the last cell of this item. + **/ + YTableCellIterator cellsEnd() { return _cells.end(); } + YTableCellConstIterator cellsEnd() const { return _cells.end(); } + + /** + * Return the cell at the specified index (counting from 0 on) + * or 0 if there is none. + **/ + const YTableCell * cell( int index ) const; + YTableCell * cell( int index ); + + /** + * Return the number of cells this item has. + **/ + int cellCount() const { return _cells.size(); } + + /** + * Return 'true' if this item has a cell with the specified index + * (counting from 0 on), 'false' otherwise. + **/ + bool hasCell( int index ) const; + + /** + * Return the label of cell no. 'index' (counting from 0 on) or an empty + * string if there is no cell with that index. + **/ + std::string label( int index ) const; + + /** + * Return the icon name of cell no. 'index' (counting from 0 on) or an empty + * string if there is no cell with that index. + **/ + std::string iconName( int index ) const; + + /** + * Return 'true' if there is a cell with the specified index that has an + * icon name. + **/ + bool hasIconName( int index ) const; + + /** + * Just for debugging. + **/ + std::string label() const { return label(0); } + +private: + + // Disable unwanted base class methods. They don't make sense in this + // context since there is not just one single label or icon name, but one + // for each cell. + + std::string iconName() const { return ""; } + bool hasIconName() const { return false; } + void setLabel ( const std::string & ) {} + void setIconName ( const std::string & ) {} + + + // + // Data members + // + + YTableCellCollection _cells; +}; + + + +/** + * One cell (one column in one row) of a YTableItem. Each cell has a label (a + * user visible text) and optionally an icon (*). + * + * Note that cells don't have individual IDs; they have just an index. + * The first cell in an item is cell(0). In an ideal world, each YTableItem + * would have exactly as many cells as there are columns in the YTable, but + * these classes make no such assumptions. A YTableItem might have any number + * of cells, including none. + * + * The YTable widget is free to ignore any excess cells if there are more than + * the YTable widget has columns. If there are less cells than the table has + * columns, the nonexistent cells will be treated as empty. + * + * + * (*) Not all UIs can handle icons. UIs that can't handle them will simply + * ignore any icons specified for YTableCells. Thus, applications should either + * check the UI capabilities if it can handle icons or use icons only as an + * additional visual cue that still has a text counterpart (so the user can + * still make sense of the table content when no icons are visible). + **/ +class YTableCell +{ +public: + /** + * Constructor with label and optional icon name for cells that don't have + * a parent item yet (that will be added to a parent later with + * setParent()). + **/ + YTableCell( const std::string & label, const std::string & iconName = "" ) + : _label( label ) + , _iconName( iconName ) + , _parent( 0 ) + , _column ( -1 ) + {} + + /** + * Constructor with parent, column no., label and optional icon name for + * cells that are created with a parent. + **/ + YTableCell( YTableItem * parent, + int column, + const std::string & label, + const std::string & iconName = "" ) + : _label( label ) + , _iconName( iconName ) + , _parent( parent ) + , _column ( column ) + {} + + /** + * Destructor. Not strictly needed inside this class, but useful for + * derived classes. Since this is the only virtual method of this class, + * the cost of this is a vtable for this class and a pointer to the vtable + * in each instance. + **/ + virtual ~YTableCell() {} + + /** + * Return this cells's label. This is what the user sees in a dialog, so + * this will usually be a translated text. + **/ + std::string label() const { return _label; } + + /** + * Set this cell's label. + * + * If this is called after the corresponding table item (table row) is + * added to the table widget, call YTable::cellChanged() to notify the + * table widget about the fact. Only then will the display be updated. + **/ + void setLabel( const std::string & newLabel ) { _label = newLabel; } + + /** + * Return this cell's icon name. + **/ + std::string iconName() const { return _iconName; } + + /** + * Return 'true' if this cell has an icon name. + **/ + bool hasIconName() const { return ! _iconName.empty(); } + + /** + * Set this cell's icon name. + * + * If this is called after the corresponding table item (table row) is + * added to the table widget, call YTable::cellChanged() to notify the + * table widget about the fact. Only then will the display be updated. + **/ + void setIconName( const std::string & newIconName ) { _iconName = newIconName; } + + /** + * Return this cell's parent item or 0 if it doesn't have one yet. + **/ + YTableItem * parent() const { return _parent; } + + /** + * Return this cell's column no. (counting from 0on) or -1 if it doesn't + * have a parent yet. + **/ + int column() const { return _column; } + + /** + * Convenience function: Return this cell's parent item's index within its + * table widget or -1 if there is no parent item or no parent table. + **/ + int itemIndex() const { return _parent ? _parent->index() : -1; } + + /** + * Set this cell's parent item and column no. if it doesn't have a parent + * yet. + * + * This method will throw an exception if the cell already has a parent. + **/ + void reparent( YTableItem * parent, int column ); + + +private: + + std::string _label; + std::string _iconName; + YTableItem * _parent; + int _column; +}; + + + + #endif // YTableItem_h diff --git a/src/YTimeField.cc b/src/YTimeField.cc new file mode 100644 index 0000000..962dadf --- /dev/null +++ b/src/YTimeField.cc @@ -0,0 +1,62 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTimeField.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YTimeField.h" + + +struct YTimeFieldPrivate +{ + YTimeFieldPrivate() + {} + + bool dummy; +}; + + + + +YTimeField::YTimeField( YWidget * parent, const std::string & label ) + : YSimpleInputField( parent, label ) + , priv( new YTimeFieldPrivate() ) +{ + YUI_CHECK_NEW( priv ); +} + + +YTimeField::~YTimeField() +{ + // NOP +} + + +/* + * Properties (all handled in YSimpleInputField): + * + * @property std::string Value the time (the field's contents) as "hh:mm:ss" + * @property std::string Label caption above the input field + */ diff --git a/src/YTimeField.h b/src/YTimeField.h new file mode 100644 index 0000000..ab2f9a3 --- /dev/null +++ b/src/YTimeField.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTimeField.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YTimeField_h +#define YTimeField_h + +#include "YSimpleInputField.h" + +class YTimeFieldPrivate; + + +/** + * Input field for entering a time in "hh:mm:ss" format. + * + * Derived classes are required to implement: + * value() + * setValue() + * See YSimpleInputField.h for details. + **/ +class YTimeField : public YSimpleInputField +{ +protected: + /** + * Constructor. + **/ + YTimeField( YWidget * parent, const std::string & label ); + +public: + /** + * Destructor. + **/ + virtual ~YTimeField(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YTimeField"; } + +private: + + ImplPtr priv; +}; + + +#endif // YTimeField_h diff --git a/src/YTimezoneSelector.cc b/src/YTimezoneSelector.cc new file mode 100644 index 0000000..9259b64 --- /dev/null +++ b/src/YTimezoneSelector.cc @@ -0,0 +1,98 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTimezoneSelector.cc + + Author: Stephan Kulow + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YTimezoneSelector.h" + + +class YTimezoneSelectorPrivate +{ + bool dummy; +}; + + + + +YTimezoneSelector::YTimezoneSelector( YWidget * parent, + const std::string &pixmap, + const std::map &timezones ) + : YWidget( parent ) +{ +} + + +YTimezoneSelector::~YTimezoneSelector() +{ + // NOP +} + + +const YPropertySet & +YTimezoneSelector::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentItem, YStringProperty ) ); + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +bool +YTimezoneSelector::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) + { + setCurrentZone( val.stringVal(), true ); + return true; // success -- no special handling necessary + } + if ( propertyName == YUIProperty_CurrentItem ) + { + setCurrentZone( val.stringVal(), false ); + return true; // success -- no special handling necessary + } + return YWidget::setProperty( propertyName, val ); +} + + +YPropertyValue +YTimezoneSelector::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( currentZone() ); + if ( propertyName == YUIProperty_CurrentItem ) return YPropertyValue( currentZone() ); + return YWidget::getProperty( propertyName ); +} diff --git a/src/YTimezoneSelector.h b/src/YTimezoneSelector.h new file mode 100644 index 0000000..fa8372a --- /dev/null +++ b/src/YTimezoneSelector.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTimezoneSelector.h + + Author: Stephan Kulow + +/-*/ + +#ifndef YTimezoneSelector_h +#define YTimezoneSelector_h + +#include +#include "YWidget.h" + + +class YTimezoneSelectorPrivate; + + +/** + * A fancy widget with a world map. + **/ +class YTimezoneSelector : public YWidget +{ +protected: + /** + * Constructor. This widget isn't doing much on it's own, but the + * UI may have some fancy use. @arg pixmap should be a png or jpg + * of a world map with centered 0°0° and the timezones are a map + * between zone.tab entry and user visible string. + * + * The widget is only displaying timezones/cities in that map + **/ + YTimezoneSelector( YWidget *parent, + const std::string &pixmap, + const std::map &timezones ); + +public: + /** + * Destructor. + **/ + virtual ~YTimezoneSelector(); + + /** + * Return a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YTimezoneSelector"; } + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * subclasses have to implement this to return value + */ + virtual std::string currentZone() const = 0; + + /** + * subclasses have to implement this to set value + */ + virtual void setCurrentZone( const std::string &zone, bool zoom ) = 0; + +private: + ImplPtr priv; + +}; + + +#endif // YMultiProgressMeter_h diff --git a/src/YTransText.h b/src/YTransText.h new file mode 100644 index 0000000..92f7707 --- /dev/null +++ b/src/YTransText.h @@ -0,0 +1,130 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTransText.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YTransText_h +#define YTransText_h + +#include +#include + + +/** + * Helper class for translated strings: Stores a message in the original + * (untranslated) version along with the translation into the current locale. + **/ +class YTransText +{ +public: + + /** + * Constructor with both original and translated message. + **/ + YTransText( const std::string & orig, + const std::string & translation ) + : _orig( orig ), _translation( translation ) {} + + /** + * Constructor that automatically translates the original message. + **/ + YTransText( const std::string & orig ) : _orig( orig ) + { + _translation = gettext( _orig.c_str() ); + } + + /** + * Copy constructor. + **/ + YTransText( const YTransText & src ) + { + _orig = src.orig(); + _translation = src.translation(); + } + + /** + * Assignment operator. + **/ + YTransText & operator= ( const YTransText & src ) + { + _orig = src.orig(); + _translation = src.translation(); + + return *this; + } + + /** + * Return the original message. + **/ + const std::string & orig() const { return _orig; } + + /** + * Return the translation. + **/ + const std::string & translation() const { return _translation; } + + /** + * Return the translation. + * ( alias, just as a shortcut ) + **/ + const std::string & trans() const { return _translation; } + + /** + * Set the original message. Does not touch the translation, so make sure + * you change both if you want to keep them synchronized! + **/ + void setOrig( const std::string & newOrig ) { _orig = newOrig; } + + /** + * Set the translation. + **/ + void setTranslation( const std::string & newTrans ) { _translation = newTrans; } + + /** + * operator< : Compares translations. + **/ + bool operator< ( const YTransText & other ) const + { return _translation < other.translation(); } + + /** + * operator> : Compares translations. + **/ + bool operator> ( const YTransText & other ) const + { return _translation > other.translation(); } + + /** + * operator== : Compares translations. + **/ + bool operator== ( const YTransText & other ) const + { return _translation == other.translation(); } + + +private: + + std::string _orig; + std::string _translation; + +}; + + + +#endif // YTransText_h diff --git a/src/YTree.cc b/src/YTree.cc new file mode 100644 index 0000000..a0442ba --- /dev/null +++ b/src/YTree.cc @@ -0,0 +1,168 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTree.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YSelectionWidget.h" +#include "YTree.h" +#include "YTreeItem.h" + +struct YTreePrivate +{ + YTreePrivate() + : immediateMode( false ) + {} + + bool immediateMode; +}; + + +YTree::YTree( YWidget * parent, const std::string & label, bool multiSelection, bool recursiveSelection ) + : YSelectionWidget( parent, label, + ! multiSelection, + recursiveSelection ) + , priv( new YTreePrivate() ) +{ + YUI_CHECK_NEW( priv ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YTree::~YTree() +{ + // NOP +} + + +bool +YTree::immediateMode() const +{ + return priv->immediateMode; +} + + +void +YTree::setImmediateMode( bool immediateMode ) +{ + priv->immediateMode = immediateMode; + + if ( immediateMode ) + setNotify( true ); +} + + +void +YTree::addItems( const YItemCollection & itemCollection ) +{ + YSelectionWidget::addItems( itemCollection ); + rebuildTree(); +} + + +const YPropertySet & +YTree::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property itemID Value The currently selected item + * @property itemID CurrentItem The currently selected item + * @property list CurrentBranch List of IDs of current branch from root to current item + * @property itemList Items All items + * @property map OpenItems Map of IDs of all open items - can only be queried, not set + * @property std::string Label Caption above the tree + * @property std::string IconPath Base path for icons + * @property bool MultiSelection Flag: User can select multiple items (read-only) + */ + propSet.add( YProperty( YUIProperty_Value, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentItem, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_CurrentBranch, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Items, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_OpenItems, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_IconPath, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_SelectedItems, YOtherProperty ) ); + propSet.add( YProperty( YUIProperty_MultiSelection, YBoolProperty, true ) ); // read-only + propSet.add( YWidget::propertySet() ); + + } + + return propSet; +} + + +bool +YTree::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + + if ( propertyName == YUIProperty_Value ) return false; // Needs special handling + else if ( propertyName == YUIProperty_CurrentItem ) return false; // Needs special handling + else if ( propertyName == YUIProperty_CurrentBranch ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Items ) return false; // Needs special handling + else if ( propertyName == YUIProperty_OpenItems ) return false; // Needs special handling + else if ( propertyName == YUIProperty_SelectedItems ) return false; // Needs special handling + else if ( propertyName == YUIProperty_Label ) setLabel( val.stringVal() ); + else if ( propertyName == YUIProperty_IconPath ) setIconBasePath( val.stringVal() ); + + else + { + return YWidget::setProperty( propertyName, val ); + } + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YTree::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_Value ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_CurrentItem ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_CurrentBranch ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Items ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_OpenItems ) return YPropertyValue( YOtherProperty ); + else if ( propertyName == YUIProperty_Label ) return YPropertyValue( label() ); + else if ( propertyName == YUIProperty_IconPath ) return YPropertyValue( iconBasePath() ); + else if ( propertyName == YUIProperty_SelectedItems ) return YPropertyValue( YOtherProperty ); + else + { + return YWidget::getProperty( propertyName ); + } +} + +bool +YTree::hasMultiSelection() const +{ + return ! YSelectionWidget::enforceSingleSelection(); +} diff --git a/src/YTree.h b/src/YTree.h new file mode 100644 index 0000000..14fa279 --- /dev/null +++ b/src/YTree.h @@ -0,0 +1,182 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTree.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YTree_h +#define YTree_h + +#include "YSelectionWidget.h" + +class YTreeItem; +class YTreePrivate; + + +/** + * Tree: List box that displays a (scrollable) list of hierarchical items from + * which the user can select exactly one. Each item has a label text and an + * optional icon (*). + * + * This is very similar to SelectionBox, but each item can have subitems that + * can be open (expanded) or closed (collapsed). + * + * The tree widget also has a caption label that is displayed above the + * tree. The hotkey displayed in that caption label will move the keyboard + * focus into the tree item list. + * + * + * (*) Not all UIs (in particular not text-based UIs) support displaying icons, + * so an icon should never be an exclusive means to display any kind of + * information. + + * 'multiSelection' indicates whether or not the user can select multiple + * items at the same time. This can only be set in the constructor. + **/ + + +class YTree : public YSelectionWidget +{ +protected: + /** + * Constructor. + **/ + YTree( YWidget * parent, const std::string & label, bool multiSelection, bool recursiveSelection); + +public: + /** + * Destructor. + **/ + virtual ~YTree(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YTree"; } + + /** + * Rebuild the displayed tree from the internally stored YTreeItems. + * + * The application should call this (once) after all items have been added + * with addItem(). YTree::addItems() calls this automatically. + * + * Derived classes are required to implement this. + **/ + virtual void rebuildTree() = 0; + + /** + * Add multiple items. For some UIs, this can be more efficient than + * calling addItem() multiple times. This function also automatically calls + * rebuildTree() at the end. + * + * Derived classes can overwrite this function, but they should call this + * base class function at the end of the new implementation. + * + * Reimplemented from YSelectionWidget. + **/ + virtual void addItems( const YItemCollection & itemCollection ); + + /** + * Deliver even more events than with notify() set. + * + * For YTree, this is relevant mostly for the NCurses UI: + * + * In graphical UIs like the Qt UI, the user can use the mouse to select an + * item in a tree. With notify() set, this will send an event right away + * (i.e., it will make UserInput and related return, while normally it + * would only return when the user clicks a PushButton). + * + * In the NCurses UI, there is no mouse, so the user has to use the cursor + * keys to move to the item he wants to select. In immediateMode(), every + * cursor key press will make the tree send an event. Without + * immediateMode(), the NCTree will wait until the user hits the [Return] + * key until an event is sent. Depending on what the application does upon + * each selection box event, immediateMode() might make the application + * less responsive. + **/ + bool immediateMode() const; + + /** + * Set immediateMode() on or off. + **/ + void setImmediateMode( bool on = true ); + + /** + * Set a property. + * Reimplemented from YWidget. + * + * This function may throw YUIPropertyExceptions. + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + /** + * The name of the widget property that will return user input. + * Inherited from YWidget. + **/ + const char * userInputProperty() { return YUIProperty_CurrentItem; } + + + /** + * Return 'true' if the user can select multiple items at the same time + **/ + bool hasMultiSelection() const; + + /** + * Return the the item that currently has the keyboard focus + * or 0 if no item currently has the keyboard focus. + * + * Notice that for a MultiSelectionBox the current item is not necessarily + * selected, i.e., its check box may or may not be checked. + * + * Derived classes are required to implement this function. + **/ + virtual YTreeItem * currentItem() = 0; + + +private: + + ImplPtr priv; +}; + + +#endif // YTree_h diff --git a/src/YTreeItem.cc b/src/YTreeItem.cc new file mode 100644 index 0000000..a37532a --- /dev/null +++ b/src/YTreeItem.cc @@ -0,0 +1,108 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTreeItem.cc + + Author: Stefan Hundhammer + +/-*/ + +#include "YTreeItem.h" + + +YTreeItem::YTreeItem( const std::string & label, + bool isOpen ) + : YItem( label ) + , _parent( 0 ) + , _isOpen( isOpen ) +{ +} + + +YTreeItem::YTreeItem( const std::string & label, + const std::string & iconName, + bool isOpen ) + : YItem( label, iconName ) + , _parent( 0 ) + , _isOpen( isOpen ) +{ +} + + +YTreeItem::YTreeItem( YTreeItem * parent, + const std::string & label, + bool isOpen ) + : YItem( label ) + , _parent( parent ) + , _isOpen( isOpen ) +{ + if ( parent ) + parent->addChild( this ); +} + + +YTreeItem::YTreeItem( YTreeItem * parent, + const std::string & label, + const std::string & iconName, + bool isOpen ) + : YItem( label, iconName ) + , _parent( parent ) + , _isOpen( isOpen ) +{ + if ( parent ) + parent->addChild( this ); +} + + +YTreeItem::~YTreeItem() +{ + deleteChildren(); +} + + +void YTreeItem::addChild( YItem * child ) +{ + _children.push_back( child ); +} + + +void YTreeItem::deleteChildren() +{ + YItemIterator it = childrenBegin(); + + while ( it != childrenEnd() ) + { + YItem * child = *it; + ++it; + delete child; + } + + _children.clear(); +} + + +bool YTreeItem::isOpen() const +{ + return hasChildren() ? _isOpen : false; +} + + +void YTreeItem::setOpen( bool open ) +{ + _isOpen = open; +} diff --git a/src/YTreeItem.h b/src/YTreeItem.h new file mode 100644 index 0000000..e3e513c --- /dev/null +++ b/src/YTreeItem.h @@ -0,0 +1,139 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YTreeItem.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YTreeItem_h +#define YTreeItem_h + +#include "YItem.h" + + + +/** + * Item class for tree items. + * + * This class implements children management. + **/ +class YTreeItem: public YItem +{ +public: + /** + * Constructors for toplevel items. + **/ + YTreeItem( const std::string & label, + bool isOpen = false ); + + YTreeItem( const std::string & label, + const std::string & iconName, + bool isOpen = false ); + + /** + * Constructors for items that have a parent item. + * + * They will automatically register this item with the parent item. The + * parent assumes ownership of this item and will delete it in its (the + * parent's) destructor. + **/ + YTreeItem( YTreeItem * parent, + const std::string & label, + bool isOpen = false ); + + YTreeItem( YTreeItem * parent, + const std::string & label, + const std::string & iconName, + bool isOpen = false ); + + /** + * Destructor. + * + * This will delete all children. + **/ + virtual ~YTreeItem(); + + /** + * Return 'true' if this item has any child items. + * + * Reimplemented from YItem. + **/ + virtual bool hasChildren() const { return ! _children.empty(); } + + /** + * Return an iterator that points to the first child item of this item. + * + * Reimplemented from YItem. + **/ + virtual YItemIterator childrenBegin() { return _children.begin(); } + virtual YItemConstIterator childrenBegin() const { return _children.begin(); } + + /** + * Return an iterator that points after the last child item of this item. + * + * Reimplemented from YItem. + **/ + virtual YItemIterator childrenEnd() { return _children.end(); } + virtual YItemConstIterator childrenEnd() const { return _children.end(); } + + /** + * Add a child item to this item. + * + * Note that the constructors that accept a parent pointer will + * automatically add themselves to their parent, so applications will + * normally not have to call this function. + **/ + virtual void addChild( YItem * item_disown ); + + /** + * Delete all child items. + **/ + virtual void deleteChildren(); + + /** + * Return 'true' if this tree item should be displayed open (with its + * children visible) by default. + * + * Notice that this will always return 'false' for tree items without + * children. + **/ + bool isOpen() const; + + /** + * Change the 'isOpen' flag. + **/ + void setOpen( bool open ); + + /** + * Returns this item's parent item or 0 if it is a toplevel item. + * + * Reimplemented from YItem. + **/ + virtual YTreeItem * parent() const { return _parent; } + +private: + + YTreeItem * _parent; + YItemCollection _children; + bool _isOpen; +}; + + +#endif // YTreeItem_h diff --git a/src/YTypes.h b/src/YTypes.h new file mode 100644 index 0000000..fce4fb1 --- /dev/null +++ b/src/YTypes.h @@ -0,0 +1,108 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/** + @file YTypes.h + + Author: Stefan Hundhammer + + Header file for frequently used simple types to reduce interdependencies + between important headers (e.g., YWidget.h, YUI.h). + +**/ + + +#ifndef YTypes_h +#define YTypes_h + +#include + +typedef double YLayoutSize_t; +typedef long long YFileSize_t; + +class YWidget; + +typedef std::list YWidgetList; +typedef std::list::iterator YWidgetListIterator; +typedef std::list::const_iterator YWidgetListConstIterator; +typedef std::list::reverse_iterator YWidgetListReverseIterator; +typedef std::list::const_reverse_iterator YWidgetListConstReverseIterator; + + +#define YUIAllDimensions 2 + +enum YUIDimension +{ + YD_HORIZ = 0, + YD_VERT = 1 +}; + + +enum YAlignmentType +{ + YAlignUnchanged, + YAlignBegin, + YAlignEnd, + YAlignCenter +}; + + +/** + * Type of dialog: Main / Popup / Wizard. + **/ +enum YDialogType +{ + YMainDialog, + YPopupDialog, + YWizardDialog, +}; + + +enum YDialogColorMode +{ + YDialogNormalColor, // Default + YDialogInfoColor, // Brighter colors + YDialogWarnColor // Very bright Warning colors +}; + + +enum YButtonRole +{ + YCustomButton = 0, // No predefined role + YOKButton, // [OK], [Continue], [Yes], [Accept], [Next] + YApplyButton, // [Apply] + YCancelButton, // [Cancel] + YHelpButton, // [Help] + YRelNotesButton, // [Release Notes] + + YMaxButtonRole // For use as array size +}; + + +enum YButtonOrder +{ + YKDEButtonOrder, // [OK] [Apply] [Cancel] [Custom1] [Custom2] [Help] + // [Yes] [No] + // [Continue] [Cancel] + + YGnomeButtonOrder // [Help] [Custom1] [Custom2] [Apply] [Cancel] [OK] + // [No] [Yes] + // [Cancel] [Continue] +}; + + + +#endif // YTypes_h diff --git a/src/YUI.cc b/src/YUI.cc new file mode 100644 index 0000000..c5f59ed --- /dev/null +++ b/src/YUI.cc @@ -0,0 +1,523 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUI.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define VERBOSE_COMM 0 // VERY verbose thread communication logging + +#include +#include // strerror() +#include // pipe() +#include // fcntl() +#include +#include +#include // getenv() + +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUI.h" +#include "YUILoader.h" +#include "YUISymbols.h" +#include "YDialog.h" +#include "YApplication.h" +#include "YMacro.h" +#include "YButtonBox.h" +#include "YEnvVar.h" +#include "YBuiltinCaller.h" +#include "YWidgetID.h" + +using std::endl; + +// Environment variable to determine button order +// (set to "KDE" or "GNOME" - case insensitive) +#define ENV_BUTTON_ORDER "Y2_BUTTON_ORDER" + +// Keep dialog stack before the YUITerminator +// so that it is destroyed afterwards. +// YUITerminator deletes _yui which calls YUI::~YUI +// which accesses the dialog stack to remove all dialogs +std::stack YDialog::_dialogStack; +YUI * YUI::_ui = 0; + +static bool uiDeleted = false; + +extern void * start_ui_thread( void * yui ); + + +YUI::YUI( bool withThreads ) + : _withThreads( withThreads ) + , _uiThread( 0 ) + , _builtinCaller( 0 ) + , _terminate_ui_thread( false ) + , _eventsBlocked( false ) +{ + yuiMilestone() << "This is libyui " << VERSION << std::endl; + yuiMilestone() << "Creating UI " << ( withThreads ? "with" : "without" ) << " threads" << endl; + _ui = this; +} + + +YUI::~YUI() +{ + if ( _ui ) + { + if ( _withThreads && _uiThread ) + { + yuiError() << "shutdownThreads() was never called!" << endl; + yuiError() << "shutting down now - this might segfault" << endl; + shutdownThreads(); + } + + if ( YDialog::openDialogsCount() > 0 ) + yuiError() << YDialog::openDialogsCount() << " open dialogs left over" << endl; + + if ( _builtinCaller ) + delete _builtinCaller; + + YDialog::deleteAllDialogs(); + + YMacro::deleteRecorder(); + YMacro::deletePlayer(); + + _ui = 0; + uiDeleted = true; + } +} + + +void +YUI::uiThreadDestructor() +{ + YDialog::deleteAllDialogs(); +} + + +YUI * +YUI::ui() +{ + ensureUICreated(); + return _ui; +} + + +YWidgetFactory * +YUI::widgetFactory() +{ + static YWidgetFactory * factory = 0; + + ensureUICreated(); + + if ( ! factory ) + factory = ui()->createWidgetFactory(); + + YUI_CHECK_PTR( factory ); + return factory; +} + + +YOptionalWidgetFactory * +YUI::optionalWidgetFactory() +{ + static YOptionalWidgetFactory * factory = 0; + + ensureUICreated(); + + if ( ! factory ) + factory = ui()->createOptionalWidgetFactory(); + + YUI_CHECK_PTR( factory ); + return factory; +} + + +YApplication * +YUI::app() +{ + static YApplication * app = 0; + + ensureUICreated(); + + if ( ! app ) + app = ui()->createApplication(); + + YUI_CHECK_PTR( app ); + return app; +} + + +void YUI::ensureUICreated() +{ + if ( _ui ) + return; + + if ( uiDeleted ) + YUI_THROW( YUIException( "UI already deleted" ) ); + + YUILoader::loadUI(); +} + + +void YUI::topmostConstructorHasFinished() +{ + // The ui thread must not be started before the constructor + // of the actual user interface is finished. Otherwise there + // is a race condition. The ui thread would go into idleLoop() + // before the ui is really setup. For example the Qt interface + // does a processOneEvent in the idleLoop(). This may do a + // repaint operation on the dialog that is just under construction! + // + // Therefore the creation of the thread is delayed and performed in this + // method. It must be called at the end of the constructor of the specific + // UI (the Qt UI or the NCurses UI). + + if ( _withThreads ) + { + if ( pipe( pipe_from_ui ) == 0 && + pipe( pipe_to_ui ) == 0 ) + { + + // Make fd non blockable the ui thread reads from + long arg; + arg = fcntl( pipe_to_ui[0], F_GETFL ); + if ( fcntl( pipe_to_ui[0], F_SETFL, arg | O_NONBLOCK ) < 0 ) + { + yuiError() << "Couldn't set O_NONBLOCK: errno: " << errno << " " << strerror( errno ) << endl; + _withThreads = false; + close( pipe_to_ui[0] ); + close( pipe_to_ui[1] ); + close( pipe_from_ui[0] ); + close( pipe_from_ui[1] ); + } + else + { +#if VERBOSE_COMM + yuiDebug() << "Inter-thread communication pipes set up" << endl; +#endif + _terminate_ui_thread = false; + createUIThread(); + } + } + else + { + yuiError() << "pipe() failed: errno: " << errno << " " << strerror( errno ) << endl; + exit(2); + } + } + else + { + yuiMilestone() << "Running without threads" << endl; + } +} + + +void YUI::createUIThread() +{ + pthread_attr_t attr; + pthread_attr_init( & attr ); + int ret = pthread_create( & _uiThread, & attr, start_ui_thread, this ); + + if ( ret != 0 ) + yuiError() << "pthread_create() failed: " << errno << " " << strerror( errno ) << endl; +} + + +void YUI::terminateUIThread() +{ + yuiDebug() << "Sending shutdown message to UI thread" << endl; + + _terminate_ui_thread = true; + signalUIThread(); + waitForUIThread(); + pthread_join( _uiThread, 0 ); + + yuiDebug() << "UI thread shut down correctly" << endl; +} + + +void YUI::shutdownThreads() +{ + if ( _uiThread ) + { + terminateUIThread(); + _uiThread = 0; + close( pipe_to_ui[0] ); + close( pipe_to_ui[1] ); + close( pipe_from_ui[0] ); + close( pipe_from_ui[1] ); + } +} + + +void YUI::signalUIThread() +{ + static char arbitrary = 42; + if ( write ( pipe_to_ui[1], & arbitrary, 1 ) == -1 ) + yuiError() << "Writing byte to UI thread failed" << endl; + +#if VERBOSE_COMM + yuiDebug() << "Wrote byte to UI thread" << endl; +#endif +} + + +bool YUI::waitForUIThread() +{ + char arbitrary; + int result; + + do { +#if VERBOSE_COMM + yuiDebug() << "Waiting for ui thread..." << endl; +#endif + result = read( pipe_from_ui[0], & arbitrary, 1 ); + if ( result == -1 ) + { + if ( errno == EINTR || errno == EAGAIN ) + continue; + else + yuiError() << "waitForUIThread: errno: " << errno << " " << strerror( errno ) << endl; + } + } while ( result == 0 ); + +#if VERBOSE_COMM + yuiDebug() << "Read byte from ui thread" << endl; +#endif + + // return true if we really did get a signal byte + return result != -1; +} + + +void YUI::signalYCPThread() +{ + static char arbitrary; + if ( write( pipe_from_ui[1], & arbitrary, 1 ) == -1 ) + yuiError() << "Writing byte to YCP thread failed" << endl; + +#if VERBOSE_COMM + yuiDebug() << "Wrote byte to YCP thread" << endl; +#endif +} + + +bool YUI::waitForYCPThread() +{ + char arbitrary; + + int result; + do { +#if VERBOSE_COMM + yuiDebug() << "Waiting for YCP thread..." << endl; +#endif + result = read( pipe_to_ui[0], & arbitrary, 1 ); + if ( result == -1 ) + { + if ( errno == EINTR || errno == EAGAIN ) + continue; + else + yuiError() << "waitForYCPThread: errno: " << errno << " " << strerror( errno ) << endl; + } + } while ( result == 0 ); + +#if VERBOSE_COMM + yuiDebug() << "Read byte from YCP thread" << endl; +#endif + + // return true if we really did get a signal byte + return result != -1; +} + + +void YUI::uiThreadMainLoop() +{ + while ( true ) + { + idleLoop( pipe_to_ui[0] ); + + // The pipe is non-blocking, so we have to check if we really read a + // signal byte. Although idleLoop already does a select(), this seems to + // be necessary. Anyway: Why do we set the pipe to non-blocking if we + // wait in idleLoop for it to become readable? It is needed in + // YUIQt::idleLoop for QSocketNotifier. + + if ( ! waitForYCPThread () ) + continue; + + if ( _terminate_ui_thread ) + { + uiThreadDestructor(); + signalYCPThread(); + yuiDebug() << "Shutting down UI main loop" << endl; + return; + } + + if ( _builtinCaller ) + _builtinCaller->call(); + else + yuiError() << "No builtinCaller set" << endl; + + signalYCPThread(); + } +} + + +void YUI::setButtonOrderFromEnvironment() +{ + YButtonOrder buttonOrder = YButtonBox::layoutPolicy().buttonOrder; + YButtonOrder oldButtonOrder = buttonOrder; + + YEnvVar lastEnv; + + // + // $DESKTOP_SESSION + // + + YEnvVar env( "DESKTOP_SESSION" ); + yuiDebug() << env << endl; + + if ( env == "kde" || + env == "xfce" ) + { + buttonOrder = YKDEButtonOrder; + lastEnv = env; + } + else if ( env == "gnome" ) + { + buttonOrder = YGnomeButtonOrder; + lastEnv = env; + } + + // + // $WINDOWMANAGER + // + + env = YEnvVar( "WINDOWMANAGER" ); + yuiDebug() << env << endl; + + if ( env.contains( "gnome" ) ) + { + buttonOrder = YGnomeButtonOrder; + lastEnv = env; + } + else if ( env.contains( "kde" ) ) + { + buttonOrder = YKDEButtonOrder; + lastEnv = env; + } + + + // + // $Y2_BUTTON_ORDER + // + + env = YEnvVar( ENV_BUTTON_ORDER ); + yuiDebug() << env << endl; + + if ( env == "gnome" ) + { + buttonOrder = YGnomeButtonOrder; + lastEnv = env; + } + else if ( env == "kde" ) + { + buttonOrder = YKDEButtonOrder; + lastEnv = env; + } + else if ( ! env.value().empty() ) + { + yuiWarning() << "Ignoring unknown value of " << env << endl; + } + + + if ( buttonOrder != oldButtonOrder ) + { + std::string buttonOrderStr; + + switch ( buttonOrder ) + { + case YKDEButtonOrder: + buttonOrderStr = "KDE"; + YButtonBox::setLayoutPolicy( YButtonBox::kdeLayoutPolicy() ); + break; + + case YGnomeButtonOrder: + buttonOrderStr = "GNOME"; + YButtonBox::setLayoutPolicy( YButtonBox::gnomeLayoutPolicy() ); + break; + + // Intentionally omitting "default" branch so GCC can catch unhandled enums + } + + yuiMilestone() << "Switching to " << buttonOrderStr + << " button order because of " << lastEnv + << endl; + } +} + + +YWidget * +YUI::sendWidgetID( const std::string & id_str ) +{ + yuiMilestone() << "Sending ID \"" << id_str << "\"" << endl; + YWidget * widget = 0; + + try + { + YDialog * dialog = YDialog::currentDialog(); // may throw + YStringWidgetID id( id_str ); + widget = dialog->findWidget( &id ); + widget->setKeyboardFocus(); + } + catch ( YUINoDialogException & ex ) + { + YUI_CAUGHT( ex ); + } + // Cascading any YUIWidgetNotFoundException one level up + + return widget; +} + + + + +// +// ---------------------------------------------------------------------- +// + +void * start_ui_thread( void * yui ) +{ + YUI * ui = (YUI *) yui; + +#if VERBOSE_COMM + yuiDebug() << "Starting UI thread" << endl; +#endif + + if ( ui ) + ui->uiThreadMainLoop(); + return 0; +} + +// EOF diff --git a/src/YUI.h b/src/YUI.h new file mode 100644 index 0000000..464ee07 --- /dev/null +++ b/src/YUI.h @@ -0,0 +1,376 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUI.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YUI_h +#define YUI_h + +#include +#include + +#include "YTypes.h" +#include "YSettings.h" + +class YApplication; +class YWidget; +class YWidgetFactory; +class YOptionalWidgetFactory; +class YEvent; +class YBuiltinCaller; +class YDialog; +class YMacroPlayer; +class YMacroRecorder; + + +/** + * Abstract base class of a libYUI user interface. + **/ +class YUI +{ + friend class YUIFunction; + friend class YUILoader; + +protected: + /** + * Constructor. + **/ + YUI( bool withThreads ); + +public: + + /** + * Destructor. + **/ + virtual ~YUI(); + + /** + * Shut down multithreading. This needs to be called before the destructor + * if the UI was created with threads. If the UI was created without + * threads, this does nothing. + **/ + void shutdownThreads(); + + /** + * Access the global UI. + **/ + static YUI * ui(); + + /** + * Return the widget factory that provides all the createXY() methods for + * standard (mandatory, i.e. non-optional) widgets. + * + * This will create the factory upon the first call and return a pointer to + * the one and only (singleton) factory upon each subsequent call. + * This may throw exceptions if the factory cannot be created. + **/ + static YWidgetFactory * widgetFactory(); + + /** + * Return the widget factory that provides all the createXY() methods for + * optional ("special") widgets and the corresponding hasXYWidget() + * methods. + * + * This will create the factory upon the first call and return a pointer to + * the one and only (singleton) factory upon each subsequent call. + * This may throw exceptions if the factory cannot be created. + **/ + static YOptionalWidgetFactory * optionalWidgetFactory(); + + /** + * Return the global YApplication object. + * + * This will create the YApplication upon the first call and return a + * pointer to the one and only (singleton) YApplication upon each + * subsequent call. This may throw exceptions if the YApplication cannot + * be created. + **/ + static YApplication * app(); + + /** + * Aliases for YUI::app() + **/ + static YApplication * application() { return app(); } + static YApplication * yApp() { return app(); } + + /** + * Make sure there is a UI (with a UI plug-in) created. + * + * If there is none yet, this will use all-default parameters to load a UI + * plug-in and create a UI (without threads). + **/ + static void ensureUICreated(); + + +protected: + + /** + * Create the widget factory that provides all the createXY() methods for + * standard (mandatory, i.e. non-optional) widgets. + * + * Derived classes are required to implement this. + **/ + virtual YWidgetFactory * createWidgetFactory() = 0; + + /** + * Create the widget factory that provides all the createXY() methods for + * optional ("special") widgets and the corresponding hasXYWidget() + * methods. + * + * Derived classes are required to implement this. + **/ + virtual YOptionalWidgetFactory * createOptionalWidgetFactory() = 0; + + /** + * Create the YApplication object that provides global methods. + * + * Derived classes are required to implement this. + **/ + virtual YApplication * createApplication() = 0; + + +public: + + /** + * Block (or unblock) events. If events are blocked, any event sent + * should be ignored until events are unblocked again. + * + * This default implementation keeps track of a simple internal flag that + * can be queried with eventsBlocked(), so if you reimplement + * blockEvents(), be sure to reimplement eventsBlocked() as well. + **/ + virtual void blockEvents( bool block = true ) { _eventsBlocked = block; } + + /** + * Unblock events previously blocked. This is just an alias for + * blockEvents( false) for better readability. + * + * Note: This method is intentionally not virtual. + **/ + void unblockEvents() { blockEvents( false ); } + + /** + * Returns 'true' if events are currently blocked. + * + * Reimplement this if you reimplement blockEvents(). + **/ + virtual bool eventsBlocked() const { return _eventsBlocked; } + + /** + * Notification that a widget is being deleted. + * This is called from the YWidget destructor. + * + * Derived classes can implement this for any clean-up actions such as + * deleting any events that might be pending for that widget. + **/ + virtual void deleteNotify( YWidget * widget ) {} + + /** + * Must be called after the constructor of the Qt/NCurses ui + * is ready. Starts the ui thread. + **/ + void topmostConstructorHasFinished(); + + /** + * Running with threads? + **/ + bool runningWithThreads() const { return _withThreads; } + + /** + * This method implements the UI thread in case it is existing. + * The loop consists of calling idleLoop, getting the next + * command from the @ref YCPUIComponent, evaluating it, which + * possibly invovles calling userInput() or pollInput() + * and writes the answer back to the other thread where the request + * came from. + **/ + void uiThreadMainLoop(); + + /** + * Return the transparent inter-thread communication. + * This will return 0 until set from the outside. + **/ + YBuiltinCaller * builtinCaller() const { return _builtinCaller; } + + /** + * Set the transparent inter-thread communication. + * Built-ins are only really called if there is a valid YBuiltinCaller set. + **/ + void setBuiltinCaller( YBuiltinCaller * caller ) + { _builtinCaller = caller; } + + /** + * UI-specific runPkgSelection method. + * + * Derived classes are required to implement this. + * + * The packageSelector's dialog will take care of the event and delete it + * when appropriate. The returned pointer is valid until the next call to + * YDialog::userInput(), YDialog::pollInput(), or YUI::runPkgSelection() or + * until the dialog with the packageSelector is destroyed. + **/ + virtual YEvent * runPkgSelection( YWidget * packageSelector ) = 0; + + /** + * Send a widget ID. This implementation simply sets the keyboard focus to + * that widget. If there is no widget with that ID, this will throw a + * YUIWidgetNotFoundException. This function returns the widget that was + * found in case the caller wants to do more with it than just set the + * keyboard focus to it. + **/ + YWidget * sendWidgetID( const std::string & id ); + + +protected: + + /** + * This virtual method is called when threads are activated in case the + * execution control is currently on the side of the module. This means + * that no UserInput() or PollInput() is pending. The module just does some + * work. The UI <-> module protocol is in the "UI waits for the next + * command" state. The UI can override this method when it wants to react + * to user input or other external events such as repaint requests from the + * X server. + * + * 'fd_ycp' file descriptor that should be used to determine when + * to leave the idle loop. As soon as it is readable, the loop must + * be left. In order to avoid polling you can combine it with other + * ui-specific fds and do a common select() call. + **/ + virtual void idleLoop( int fd_ycp ) = 0; + + /** + * Tells the ui thread that it should terminate and waits + * until it does so. + **/ + void terminateUIThread(); + + /** + * Creates and launches the ui thread. + **/ + void createUIThread(); + friend void *start_ui_thread( void *ui_int ); + + /** + * Destructor for the UI thread. This will be called as the last thing the + * UI thread does. + * + * Derived classes can overwrite this. In most cases it makes sense to call + * this base class method in the new implementation. + **/ + virtual void uiThreadDestructor(); + + /** + * Signals the ui thread by sending one byte through the pipe + * to it. + **/ + void signalUIThread(); + + /** + * Waits for the ui thread to send one byte through the pipe + * to the ycp thread and reads this byte from the pipe. + **/ + bool waitForUIThread(); + + /** + * Signals the ycp thread by sending one byte through the pipe + * to it. + **/ + void signalYCPThread(); + + /** + * Waits for the ycp thread to send one byte through the pipe + * to the ycp thread and reads this byte from the pipe. + **/ + bool waitForYCPThread(); + + /** + * Set the button order (in YButtonBox widgets) from environment + * variables: + * + * $Y2_BUTTON_ORDER="KDE" + * $Y2_BUTTON_ORDER="Gnome" + * + * (all case insensitive) + **/ + void setButtonOrderFromEnvironment(); + + + // + // Data members + // + + /** + * true if a seperate UI thread is created + **/ + bool _withThreads; + + /** + * Handle to the ui thread. + **/ + pthread_t _uiThread; + + /** + * Inter-thread communication between the YCP thread and the UI thread: + * The YCP thread supplies data here and signals the UI thread, + * the UI thread picks up the data, executes the function, puts + * the result here and signals the YCP thread that waits until + * the result is available. + **/ + YBuiltinCaller * _builtinCaller; + + /** + * Used to synchronize data transfer with the ui thread. + * It stores a pair of file descriptors of a pipe. For each YCP value + * we send to the ui thread, we write one aribrary byte here. + **/ + int pipe_to_ui[2]; + + /** + * Used to synchronize data transfer with the ui thread. + * It stores a pair of file descriptors of a pipe. For each YCP value + * we get from the ui thread, we read one aribrary byte from here. + **/ + int pipe_from_ui[2]; + + /** + * This is a flag that signals the ui thread that it should + * terminate. This is done by setting the flag to true. The ui + * thread replies by setting the flag back to false directly + * after terminating itself. + **/ + bool _terminate_ui_thread; + + /** + * Flag that keeps track of blocked events. + * Never query this directly, use eventsBlocked() instead. + **/ + bool _eventsBlocked; + +private: + + static YUI * _ui; +}; + + + +#endif // YUI_h diff --git a/src/YUIException.cc b/src/YUIException.cc new file mode 100644 index 0000000..17555dd --- /dev/null +++ b/src/YUIException.cc @@ -0,0 +1,209 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUIException.cc + + Stolen from zypp/libzypp/base/Exception.cc + + Author: Michael Andres + Maintainer: Stefan Hundhammer + +/-*/ + +#include +#include // strerror() +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUIException.h" +#include "YWidget.h" + + + + +std::string YCodeLocation::asString() const +{ + std::string str( _file ); + str += "(" + _func + "):"; + + char formatted_number[ 20 ]; + sprintf( formatted_number, "%u", _line ); + + str += formatted_number; + + return str; +} + + +std::ostream & +operator<<( std::ostream & str, const YCodeLocation & obj ) +{ + return str << obj.asString(); +} + + +YUIException::YUIException() +{ + // NOP +} + +YUIException::YUIException( const std::string & msg_r ) + : _msg( msg_r ) +{ + // NOP +} + + +YUIException::~YUIException() throw() +{ + // NOP +} + + +std::string +YUIException::asString() const +{ + std::ostringstream str; + dumpOn( str ); + return str.str(); +} + + +std::ostream & +YUIException::dumpOn( std::ostream & str ) const +{ + return str << _msg; +} + + +std::ostream & +YUIException::dumpError( std::ostream & str ) const +{ + return dumpOn( str << _where << ": " ); +} + + +std::ostream & +operator<<( std::ostream & str, const YUIException & obj ) +{ + return obj.dumpError( str ); +} + + +std::string +YUIException::strErrno( int errno_r ) +{ + return strerror( errno_r ); +} + + +std::string +YUIException::strErrno( int errno_r, const std::string & msg ) +{ + std::string ret( msg ); + ret += ": "; + return ret += strErrno( errno_r ); +} + + +void +YUIException::log( const YUIException & exception, + const YCodeLocation & location, + const char * const prefix ) +{ + YUILog::warning( YUILogComponent, + location.file().c_str(), + location.line(), + location.func().c_str() ) + << "\t" << prefix << " " << exception.asString() << std::endl; +} + + +std::ostream & +YUIUnknownPropertyException::dumpOn( std::ostream & str ) const +{ + if ( widget() ) + { + return str << widget()->widgetClass() + << " has no property named \"" + << property().name() + << "\"" + << std::endl; + } + else + { + return str << "Unknown property name \"" + << property().name() + << "\"" + << std::endl; + } +} + + +std::ostream & +YUIPropertyTypeMismatchException::dumpOn( std::ostream & str ) const +{ + std::string widgetClass; + + if ( widget() ) + widgetClass = std::string( widget()->widgetClass() ) + "::"; + + return str << "Property type mismatch: " + << widgetClass + << property().name() + << " is type " + << property().typeAsStr() + << ", not " + << YProperty::typeAsStr( type() ) + << std::endl; +} + + +std::ostream & +YUISetReadOnlyPropertyException::dumpOn( std::ostream & str ) const +{ + std::string widgetClass; + + if ( widget() ) + widgetClass = std::string( widget()->widgetClass() ) + "::"; + + return str << "Property " + << widgetClass + << property().name() + << "is read-only!" + << std::endl; +} + + +std::ostream & +YUIBadPropertyArgException::dumpOn( std::ostream & str ) const +{ + std::string widgetClass; + + if ( widget() ) + widgetClass = std::string( widget()->widgetClass() ) + "::"; + + return str << "Bad argument for property " + << widgetClass + << property().name() + << ": " + << msg() + << std::endl; +} diff --git a/src/YUIException.h b/src/YUIException.h new file mode 100644 index 0000000..71b0238 --- /dev/null +++ b/src/YUIException.h @@ -0,0 +1,957 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUIException.h + + Stolen from zypp/libzypp/base/Exception.h + + Author: Michael Andres + Maintainer: Stefan Hundhammer + +/-*/ + +#ifndef YUIException_h +#define YUIException_h + + +#include +#include +#include + +#include "YProperty.h" + + +class YWidget; + + +// +// Macros for application use +// + +/** + * Usage summary: + * + * Use YUI_THROW to throw exceptions. + * Use YUI_CAUGHT If you caught an exceptions in order to handle it. + * Use YUI_RETHROW to rethrow a caught exception. + * + * The use of these macros is not mandatory. but YUI_THROW and YUI_RETHROW will + * adjust the code location information stored in the exception. All three + * macros will drop a line in the log file. + * + * 43 try + * 44 { + * 45 try + * 46 { + * 47 YUI_THROW( YUIException("Something bad happened.") ); + * 48 } + * 49 catch( YUIException & exception ) + * 50 { + * 51 YUI_RETHROW( exception ); + * 52 } + * 53 } + * 54 catch( YUIException & exception ) + * 55 { + * 56 YUI_CAUGHT( exception ); + * 57 } + * + * The above produces the following log lines: + * + * Main.cc(main):47 THROW: Main.cc(main):47: Something bad happened. + * Main.cc(main):51 RETHROW: Main.cc(main):47: Something bad happened. + * Main.cc(main):56 CAUGHT: Main.cc(main):51: Something bad happened. + **/ + + +/** + * Create YCodeLocation object storing the current location. + **/ +#define YUI_EXCEPTION_CODE_LOCATION YCodeLocation(__FILE__,__FUNCTION__,__LINE__) + + +/** + * Drops a log line and throws the YUIException. + **/ +#define YUI_THROW( EXCEPTION ) \ + _YUI_THROW( ( EXCEPTION ), YUI_EXCEPTION_CODE_LOCATION ) + +/** + * Drops a log line telling the YUIException was caught and handled. + **/ +#define YUI_CAUGHT( EXCEPTION ) \ + _YUI_CAUGHT( ( EXCEPTION ), YUI_EXCEPTION_CODE_LOCATION ) + + +/** + * Drops a log line and rethrows, updating the YCodeLocation. + **/ +#define YUI_RETHROW( EXCEPTION ) \ + _YUI_RETHROW( ( EXCEPTION ), YUI_EXCEPTION_CODE_LOCATION ) + + +/** + * Throw YUIException built from a message string. + **/ +#define YUI_THROW_MSG( EXCEPTION_TYPE, MSG ) \ + YUI_THROW( EXCEPTION_TYPE( MSG ) ) + + +/** + * Throw YUIException built from errno. + **/ +#define YUI_THROW_ERRNO( EXCEPTION_TYPE ) \ + YUI_THROW( EXCEPTION_TYPE( YUIException::strErrno( errno ) ) ) + +/** + * Throw YUIException built from errno provided as argument. + **/ +#define YUI_THROW_ERRNO1( EXCEPTION_TYPE, ERRNO ) \ + YUI_THROW( EXCEPTION_TYPE( YUIException::strErrno( ERRNO ) ) ) + +/** + * Throw YUIException built from errno and a message string. + **/ +#define YUI_THROW_ERRNO_MSG( EXCEPTION_TYPE, MSG) \ + YUI_THROW( EXCEPTION_TYPE( YUIException::strErrno( errno, MSG ) ) ) + +/** + * Throw YUIException built from errno provided as argument and a message string. + **/ +#define YUI_THROW_ERRNO_MSG1( EXCEPTION_TYPE, ERRNO,MSG ) \ + YUI_THROW( EXCEPTION_TYPE( YUIException::strErrno( ERRNO, MSG ) ) ) + + +// +// Higher-level (UI specific) exception macros +// + +/** + * Check if an instance returned by operator new is valid (nonzero). + * Throws YUIOutOfMemoryException if it is 0. + **/ +#define YUI_CHECK_NEW( PTR ) \ + do \ + { \ + if ( ! (PTR) ) \ + { \ + YUI_THROW( YUIOutOfMemoryException() ); \ + } \ + } while( 0 ) + + + +/** + * Check for null pointer. + * Throws YUINullPointerException if the pointer is 0. + **/ +#define YUI_CHECK_PTR( PTR ) \ + do \ + { \ + if ( ! (PTR) ) \ + { \ + YUI_THROW( YUINullPointerException() ); \ + } \ + } while( 0 ) + + +/** + * Check if a widget pointer is valid. + * Throws YUIInvalidWidgetException if it is 0 or invalid (already deleted). + * + * Explicitly casting the memory-address stored in the given pointer to + * a boolean-type for null-pointer-checks is needed for GCC >= 6, because + * it introduces new optimizations to remove null-pointer-checks for 'this'. + * + * Not explicitly casting the pointer's memory-address, will cause the + * compilation to fail with an error, when using this macro in YDialog: + * + * …/src/YDialog.cc: In member function 'bool YDialog::destroy(bool)': + * …/src/YDialog.cc:254:24: error: + * nonnull argument 'this' compared to NULL [-Werror=nonnull-compare] + * YUI_CHECK_WIDGET( this ); + * ~~~~~~~~~^~~~~~ + * + * See: https://gcc.gnu.org/gcc-6/porting_to.html + **/ +#define YUI_CHECK_WIDGET( WIDGET ) \ + do \ + { \ + if ( ! ( static_cast (WIDGET) ) || \ + ! (WIDGET)->isValid() ) \ + { \ + YUI_THROW( YUIInvalidWidgetException() ); \ + } \ + } while( 0 ) + + +/** + * Check if an index is in range: + * VALID_MIN <= INDEX <= VALID_MAX + * + * Throws YUIInvalidWidgetException if out of range. + **/ +#define YUI_CHECK_INDEX_MSG( INDEX, VALID_MIN, VALID_MAX, MSG ) \ + do \ + { \ + if ( (INDEX) < (VALID_MIN) || \ + (INDEX) > (VALID_MAX) ) \ + { \ + YUI_THROW( YUIIndexOutOfRangeException( (INDEX), (VALID_MIN), (VALID_MAX), (MSG) ) ); \ + } \ + } while( 0 ) + + +#define YUI_CHECK_INDEX( INDEX, VALID_MIN, VALID_MAX ) \ + YUI_CHECK_INDEX_MSG( (INDEX), (VALID_MIN), (VALID_MAX), "") + + + + +/** + * Helper class for UI exceptions: Store _FILE_, _FUNCTION_ and _LINE_. + * Construct this using the YUI_EXCEPTION_CODE_LOCATION macro. + **/ +class YCodeLocation +{ +public: + /** + * Constructor. + * Commonly called using the YUI_EXCEPTION_CODE_LOCATION macro. + **/ + YCodeLocation( const std::string & file_r, + const std::string & func_r, + int line_r ) + : _file( file_r ) + , _func( func_r ) + , _line( line_r ) + {} + + /** + * Default constructor. + ***/ + YCodeLocation() + : _line( 0 ) + {} + + /** + * Returns the source file name where the exception occured. + **/ + std::string file() const { return _file; } + + /** + * Returns the name of the function where the exception occured. + **/ + std::string func() const { return _func; } + + /** + * Returns the source line number where the exception occured. + **/ + int line() const { return _line; } + + /** + * Returns the location in normalized string format. + **/ + std::string asString() const; + + /** + * Stream output + **/ + friend std::ostream & operator<<( std::ostream & str, const YCodeLocation & obj ); + +private: + std::string _file; + std::string _func; + int _line; + +}; // YCodeLocation + + +/** + * YCodeLocation stream output + **/ +std::ostream & operator<<( std::ostream & str, const YCodeLocation & obj ); + + +/** + * Base class for UI Exceptions. + * + * Exception offers to store a message string passed to the constructor. + * Derived classes may provide additional information. + * Overload dumpOn to provide a proper error text. + **/ +class YUIException : public std::exception +{ +public: + /** + * Default constructor. + * Use YUI_THROW to throw exceptions. + **/ + YUIException(); + + /** + * Constructor taking a message. + * Use YUI_THROW to throw exceptions. + **/ + YUIException( const std::string & msg_r ); + + /** + * Destructor. + **/ + virtual ~YUIException() throw(); + + /** + * Return YCodeLocation. + **/ + const YCodeLocation & where() const + { return _where; } + + /** + * Exchange location on rethrow. + **/ + void relocate( const YCodeLocation & newLocation ) const + { _where = newLocation; } + + /** + * Return the message string provided to the constructor. + * Note: This is not neccessarily the complete error message. + * The whole error message is provided by asString or dumpOn. + **/ + const std::string & msg() const + { return _msg; } + + /** + * Set a new message string. + **/ + void setMsg( const std::string & msg ) + { _msg = msg; } + + /** + * Error message provided by dumpOn as string. + **/ + std::string asString() const; + + /** + * Make a string from errno_r. + **/ + static std::string strErrno( int errno_r ); + + /** + * Make a string from errno_r and msg_r. + **/ + static std::string strErrno( int errno_r, const std::string & msg ); + + /** + * Drop a log line on throw, catch or rethrow. + * Used by YUI_THROW macros. + **/ + static void log( const YUIException & exception, + const YCodeLocation & location, + const char * const prefix ); + /** + * Return message string. + * + * Reimplemented from std::exception. + **/ + virtual const char * what() const throw() + { return _msg.c_str(); } + +protected: + + /** + * Overload this to print a proper error message. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const; + + +private: + friend std::ostream & operator<<( std::ostream & str, const YUIException & obj ); + + + mutable YCodeLocation _where; + std::string _msg; + + /** + * Called by std::ostream & operator<<() . + * Prints YCodeLocation and the error message provided by dumpOn. + **/ + std::ostream & dumpError( std::ostream & str ) const; + +}; // class YUIException + + +/** + * YUIException stream output + **/ +std::ostream & operator<<( std::ostream & str, const YUIException & obj ); + + +/** + * Exception class for generic null pointer exceptions. + * When available, a more specialized exception class should be used. + **/ +class YUINullPointerException: public YUIException +{ +public: + YUINullPointerException() + : YUIException( "Null pointer" ) + {} + + virtual ~YUINullPointerException() throw() + {} +}; + + +/** + * Exception class for "out of memory". + * Typically used if operator new returned 0. + **/ +class YUIOutOfMemoryException: public YUIException +{ +public: + YUIOutOfMemoryException() + : YUIException( "Out of memory" ) + {} + + virtual ~YUIOutOfMemoryException() throw() + {} + +}; + +/** + * Exception class for invalid widgets. + * This is typically caused by widget pointers that continue living after the + * corresponding widget has already been deleted. + **/ +class YUIInvalidWidgetException: public YUIException +{ +public: + YUIInvalidWidgetException() + : YUIException( "Invalid widget" ) + {} + + virtual ~YUIInvalidWidgetException() throw() + {} +}; + + +/** + * Exception class for "No widget found with that ID". + **/ +class YUIWidgetNotFoundException: public YUIException +{ +public: + YUIWidgetNotFoundException( const std::string & idString ) + : YUIException( std::string( "No widget with ID " ) + idString ) + {} + + virtual ~YUIWidgetNotFoundException() throw() + {} +}; + + +class YUINoDialogException: public YUIException +{ +public: + YUINoDialogException() + : YUIException( "No dialog existing" ) + {} + + virtual ~YUINoDialogException() throw() + {} +}; + + +class YUIDialogStackingOrderException: public YUIException +{ +public: + YUIDialogStackingOrderException() + : YUIException( "Dialog stacking order violated" ) + {} + + virtual ~YUIDialogStackingOrderException() throw() + {} +}; + + +class YUISyntaxErrorException: public YUIException +{ +public: + YUISyntaxErrorException( const std::string & msg ) + : YUIException( msg ) + {} + + virtual ~YUISyntaxErrorException() throw() + {} +}; + + +/** + * Abstract base class for widget property exceptions. + **/ +class YUIPropertyException: public YUIException +{ +protected: + YUIPropertyException( const YProperty & prop, + YWidget * widget = 0 ) + : YUIException() + , _property( prop ) + , _widget( widget ) + {} + + virtual ~YUIPropertyException() throw() + {} + +public: + /** + * Returns the property that caused this exception. + **/ + YProperty property() const { return _property; } + + /** + * Returns the corresponding widget or 0 if there was none. + **/ + YWidget * widget() const { return _widget; } + + /** + * Set the corresponding widget. + **/ + void setWidget( YWidget * w ) { _widget = w; } + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const = 0; + +private: + YProperty _property; + YWidget * _widget; +}; + + +/** + * Exception class for "unknown property name": + * The application tried to set (or query) a property that doesn't exist. + **/ +class YUIUnknownPropertyException: public YUIPropertyException +{ +public: + YUIUnknownPropertyException( const std::string & propertyName, + YWidget * widget = 0 ) + : YUIPropertyException( YProperty( propertyName, YUnknownPropertyType ), widget ) + {} + + virtual ~YUIUnknownPropertyException() throw() + {} + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const; +}; + + +/** + * Exception class for "property type mismatch": + * The application tried to set a property with a wrong type. + **/ +class YUIPropertyTypeMismatchException: public YUIPropertyException +{ +public: + + YUIPropertyTypeMismatchException( const YProperty & property, + YPropertyType type, + YWidget * widget = 0 ) + : YUIPropertyException( property, widget ) + , _type( type ) + {} + + virtual ~YUIPropertyTypeMismatchException() throw() + {} + + /** + * Return the property type the application tried to set. + **/ + YPropertyType type() const { return _type; } + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const; + +private: + YPropertyType _type; +}; + + +/** + * Exception class for attempt to set a read-only property. + **/ +class YUISetReadOnlyPropertyException: public YUIPropertyException +{ +public: + + YUISetReadOnlyPropertyException( const YProperty & property, + YWidget * widget = 0 ) + : YUIPropertyException( property, widget ) + {} + + virtual ~YUISetReadOnlyPropertyException() throw() + {} + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const; +}; + + +class YUIBadPropertyArgException: public YUIPropertyException +{ +public: + + YUIBadPropertyArgException( const YProperty & property, + YWidget * widget, + const std::string & message = "" ) + : YUIPropertyException( property, widget ) + { setMsg( message ); } + + virtual ~YUIBadPropertyArgException() throw() + {} + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const; +}; + + +/** + * Exception class for "too many children": + * Attempt to add a child to a widget class that can't handle children + * (YPushButton etc.) or just one child (YFrame, YDialog). + **/ +template class YUITooManyChildrenException: public YUIException +{ +public: + + YUITooManyChildrenException( YWidget * container ) + : YUIException( "Too many children" ) + , _container( container ) + {} + + virtual ~YUITooManyChildrenException() throw() + {} + + /** + * Returns the container widget that can't handle that many children. + **/ + YWidget * container() const { return _container; } + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const + { + std::string widgetClass = + container() ? container()->widgetClass() : + "widget"; + + return str << "Too many children for " + << widgetClass + << std::endl; + } + +private: + + YWidget * _container; +}; + + +/** + * Exception class for "invalid child". One of: + * + * - Attempt to remove a child from a children manager that is not in that + * manager's children list. + * + * - Child widget of wrong type added to a container widget, e.g., anything + * other than a YPushButton added to a YButtonBox. + **/ +template class YUIInvalidChildException: public YUIException +{ +public: + + YUIInvalidChildException( YWidget * container, + YWidget * child = 0 ) + : YUIException( "Invalid child" ) + , _container( container ) + , _child( child ) + {} + + virtual ~YUIInvalidChildException() throw() + {} + + /** + * Returns the container widget whose child should be removed etc. + **/ + YWidget * container() const { return _container; } + + /** + * Returns the child widget. + **/ + YWidget * child() const { return _child; } + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const + { + std::string containerWidgetClass = + container() ? container()->widgetClass() : + "widget"; + + std::string childWidgetClass = + child() ? child()->widgetClass() : + ""; + + return str << childWidgetClass + << " is not a child of " + << containerWidgetClass + << std::endl; + } + +private: + + YWidget * _container; + YWidget * _child; +}; + + + +/** + * Exception class for "optional widget not supported". + * + * Note that applications are supposed to check with + * YUI::optionalWidgetFactory()->hasXYWidget() before trying to create such a + * widget. This exception is thrown if that check wasn't done, the application + * tried to create that kind of widget anyway, but the UI doesn't support that + * widget. + **/ +class YUIUnsupportedWidgetException: public YUIException +{ +public: + + YUIUnsupportedWidgetException( const std::string & widgetType ) + : YUIException( std::string( "Unsupported optional widget type: " ) + widgetType ) + {} + + virtual ~YUIUnsupportedWidgetException() throw() + {} +}; + + +/** + * Exception class for "value other than YD_HORIZ or YD_VERT used for + * dimension". + **/ +class YUIInvalidDimensionException: public YUIException +{ +public: + YUIInvalidDimensionException() + : YUIException( "Invalid dimension (neither YD_HORIZ nor YD_VERT)" ) + {} + + virtual ~YUIInvalidDimensionException() throw() + {} +}; + + +/** + * Exception class for "index out of range" + **/ +class YUIIndexOutOfRangeException: public YUIException +{ +public: + /** + * Constructor. + * + * 'invalidIndex' is the offending index value. It should be between + *'validMin' and 'validMax': + * + * validMin <= index <= validMax + **/ + YUIIndexOutOfRangeException( int invalidIndex, + int validMin, + int validMax, + const std::string & msg = "" ) + : YUIException( msg ) + , _invalidIndex( invalidIndex ) + , _validMin( validMin ) + , _validMax( validMax ) + {} + + virtual ~YUIIndexOutOfRangeException() throw() + {} + + /** + * Return the offending index value. + **/ + int invalidIndex() const { return _invalidIndex; } + + /** + * Return the valid minimum index. + **/ + int validMin() const { return _validMin; } + + /** + * Return the valid maximum index. + **/ + int validMax() const { return _validMax; } + +protected: + + /** + * Write proper error message with all relevant data. + * Reimplemented from YUIException. + **/ + virtual std::ostream & dumpOn( std::ostream & str ) const + { + std::string prefix = msg(); + + if ( prefix.empty() ) + prefix = "Index out of range"; + + return str << prefix << ": " << _invalidIndex + << " valid: " << _validMin << " .. " << _validMax + << std::endl; + } + +private: + + int _invalidIndex; + int _validMin; + int _validMax; +}; + + +/** + * Exception class for plugin load failure + **/ +class YUIPluginException: public YUIException +{ +public: + YUIPluginException( const std::string & pluginName ) + : YUIException( std::string( "Couldn't load plug-in " ) + pluginName ) + {} + + virtual ~YUIPluginException() throw() + {} +}; + + +/** + * Exception class for UI plugin load failure + **/ +class YUICantLoadAnyUIException: public YUIException +{ +public: + YUICantLoadAnyUIException() + : YUIException( "No $DISPLAY and stdout is not a tty" ) + {} + + virtual ~YUICantLoadAnyUIException() throw() + {} +}; + + +/** + * Exception class for "wrong button roles in YButtonBox" + **/ +class YUIButtonRoleMismatchException: public YUIException +{ +public: + + YUIButtonRoleMismatchException( const std::string & msg ) + : YUIException( msg ) + {} + + virtual ~YUIButtonRoleMismatchException() throw() + {} +}; + + +// +// Helper templates +// + + +/** + * Helper for YUI_THROW() + **/ +template +void _YUI_THROW( const _Exception & exception_r, const YCodeLocation & where_r ) +{ + exception_r.relocate( where_r ); + YUIException::log( exception_r, where_r, "THROW: " ); + throw( exception_r ); +} + + +/** + * Helper for YUI_CAUGHT() + **/ +template +void _YUI_CAUGHT( const _Exception & exception_r, const YCodeLocation & where_r ) +{ + YUIException::log( exception_r, where_r, "CAUGHT: " ); +} + + +/** + * Helper for YUI_RETHROW() + **/ +template +void _YUI_RETHROW( const _Exception & exception_r, const YCodeLocation & where_r ) +{ + YUIException::log( exception_r, where_r, "RETHROW: " ); + exception_r.relocate( where_r ); + throw; +} + + +#endif // YUIException_h diff --git a/src/YUILoader.cc b/src/YUILoader.cc new file mode 100644 index 0000000..5177137 --- /dev/null +++ b/src/YUILoader.cc @@ -0,0 +1,258 @@ +/* + Copyright (C) 2000-2017 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUILoader.cc + + Author: Stefan Hundhammer + +/-*/ + +#include // getenv() +#include // isatty()a +#include +#include + +#define YUILogComponent "ui" +#include "YUILog.h" +#include "YCommandLine.h" +#include "YUILoader.h" +#include "YUIPlugin.h" +#include "YUIException.h" +#include "YPath.h" +#include "YSettings.h" + +#include "Libyui_config.h" + + +void YUILoader::loadUI( bool withThreads ) +{ + bool isGtk = false; + const char * envDesktop = getenv( "XDG_CURRENT_DESKTOP" ) ?: ""; + const char * envDisplay = getenv( "DISPLAY" ) ?: ""; + const char * envPreset = getenv( "YUI_PREFERED_BACKEND" ) ?: ""; + std::string wantedGUI; + + yuiMilestone () << "DISPLAY: \"" << envDisplay << "\"" << std::endl; + yuiMilestone () << "XDG_CURRENT_DESKTOP: \"" << envDesktop << "\"" << std::endl; + yuiMilestone () << "YUI_PREFERED_BACKEND: \"" << envPreset << "\"" << std::endl; + + // Taken from: https://specifications.freedesktop.org/menu-spec/menu-spec-1.1.html#onlyshowin-registry + isGtk = ( ( strstr( envDesktop, "Cinnamon" ) != NULL ) || isGtk ); + isGtk = ( ( strstr( envDesktop, "GNOME" ) != NULL ) || isGtk ); + isGtk = ( ( strstr( envDesktop, "LXDE" ) != NULL ) || isGtk ); + isGtk = ( ( strstr( envDesktop, "MATE" ) != NULL ) || isGtk ); + isGtk = ( ( strstr( envDesktop, "Pantheon" ) != NULL ) || isGtk ); + isGtk = ( ( strstr( envDesktop, "ROX" ) != NULL ) || isGtk ); + isGtk = ( ( strstr( envDesktop, "Unity" ) != NULL ) || isGtk ); + isGtk = ( ( strstr( envDesktop, "XFCE" ) != NULL ) || isGtk ); + + if( isGtk ) yuiMilestone () << "Detected a Gtk-based desktop environment." << std::endl + << "Prefering Gtk-UI if available and no" << std::endl + << "user-selected override is present." << std::endl; + + YCommandLine cmdline; + + bool wantGtk = ( cmdline.find( "--gtk" ) != -1 ); + bool wantNcurses = ( cmdline.find( "--ncurses" ) != -1 ); + bool wantQt = ( cmdline.find( "--qt" ) != -1 ); + bool haveUIPreset = ( wantGtk || wantNcurses || wantQt ); + + if( !haveUIPreset ) + { + wantGtk = ( strcmp( envPreset, YUIPlugin_Gtk ) == 0 ); + wantNcurses = ( strcmp( envPreset, YUIPlugin_NCurses ) == 0 ); + wantQt = ( strcmp( envPreset, YUIPlugin_Qt ) == 0 ); + } + + if( wantGtk ) wantedGUI = YUIPlugin_Gtk; + if( wantNcurses ) wantedGUI = YUIPlugin_NCurses; + if( wantQt ) wantedGUI = YUIPlugin_Qt; + + yuiMilestone () << "User-selected UI-plugin: \"" << wantedGUI << "\"" << std::endl; + + bool haveGtk = pluginExists( YUIPlugin_Gtk ); + bool haveNcurses = pluginExists( YUIPlugin_NCurses ); + bool haveQt = pluginExists( YUIPlugin_Qt ); + + // This reset is intentional, so the loader can work it's magic + // selecting an UI-plugin as described in the documentation. + wantedGUI=""; + + // Set the UI-Plugin + if ( ( haveGtk || haveQt ) && strcmp ( envDisplay, "" ) && + ( !wantNcurses || !isatty( STDOUT_FILENO ) ) ) + { + // Qt is default if available. + if ( haveQt ) + wantedGUI = YUIPlugin_Qt; + + // Do we want to use Gtk instead? + if ( haveGtk && ( ( ( isGtk || wantGtk ) && !wantQt ) || !haveQt ) ) + wantedGUI = YUIPlugin_Gtk; + } + + else if ( haveNcurses && isatty( STDOUT_FILENO ) ) + { + // We use NCurses. + wantedGUI = YUIPlugin_NCurses; + } + + // Load the wanted UI-plugin. + if( wantedGUI != "" ) + { + yuiMilestone () << "Using UI-plugin: \"" << wantedGUI << "\""<< std::endl; + YSettings::loadedUI( wantedGUI, true ); + + try + { + loadPlugin( wantedGUI, withThreads ); + return; + } + + catch ( YUIException & ex ) + { + YUI_CAUGHT( ex ); + + // Default to NCurses, if possible. + if( wantedGUI != YUIPlugin_NCurses && haveNcurses && isatty( STDOUT_FILENO ) ) + { + yuiWarning () << "Defaulting to: \"" << YUIPlugin_NCurses << "\""<< std::endl; + YSettings::loadedUI( YUIPlugin_NCurses, true ); + + try + { + loadPlugin( YUIPlugin_NCurses, withThreads ); + return; + } + + catch ( YUIException & ex ) + { + YUI_CAUGHT( ex ); + } + } + + YUI_RETHROW( ex ); // what else to do here? + } + } + + else + { + YUI_THROW( YUICantLoadAnyUIException() ); + } +} + +void YUILoader::deleteUI() +{ + if ( YUI::_ui ) + { + yuiMilestone() << "Shutting down UI" << std::endl; + delete YUI::_ui; + + YUI::_ui = 0; + } +} + +void YUILoader::loadPlugin( const std::string & name, bool withThreads ) +{ + YUIPlugin uiPlugin( name.c_str() ); + + if ( uiPlugin.success() ) + { + createUIFunction_t createUI = (createUIFunction_t) uiPlugin.locateSymbol( "_Z8createUIb" ); // createUI(bool) + + if ( createUI ) + { + YUI * ui = createUI( withThreads ); // no threads + + // At this point the concrete UI will have loaded its own + // internal plugins and registered their destructors. + // Our destructor must get called before those get dlclose'd. + // + // Formerly ~YUI was called quite late, which called ~YQUI + // and that ran code in the already unloaded Qt internal plugins. + atexit(deleteUI); + + if ( ui ) + return; + } + } + + YUI_THROW( YUIPluginException( name ) ); +} + +void YUILoader::loadExternalWidgetsPlugin ( const std::string& name, const std::string& plugin_name, const std::string& symbol ) +{ + YUIPlugin uiPlugin ( plugin_name.c_str() ); + + if ( uiPlugin.success() ) + { + createEWFunction_t createEW = ( createEWFunction_t ) uiPlugin.locateSymbol ( symbol.c_str() ); + + if ( createEW ) + { + YExternalWidgets * we = createEW ( name.c_str() ); + + if ( we ) + return; + } + } + + YUI_THROW ( YUIPluginException ( plugin_name ) ); +} + +void YUILoader::loadExternalWidgets ( const std::string& name, const std::string& symbol ) +{ + std::string wantedGUI = name; + wantedGUI.append( "-" ); + wantedGUI.append( YSettings::loadedUI() ); + + bool haveExternal = pluginExists( wantedGUI ); + + if( haveExternal ) + { + try + { + loadExternalWidgetsPlugin(name, wantedGUI, symbol ); + return; + } + catch ( YUIException & ex ) + { + YUI_CAUGHT( ex ); + YUI_RETHROW( ex ); // what else to do here? + } + } + + else + { + YUI_THROW( YUICantLoadAnyUIException() ); + } +} + +bool YUILoader::pluginExists( const std::string & pluginBaseName ) +{ + struct stat fileinfo; + std::string pluginName = PLUGIN_PREFIX; + + pluginName.append( pluginBaseName ); + pluginName.append( PLUGIN_SUFFIX ); + + YPath plugin ( PLUGINDIR, pluginName ); + + return stat( plugin.path().c_str(), &fileinfo) == 0; + +} diff --git a/src/YUILoader.h b/src/YUILoader.h new file mode 100644 index 0000000..d9c2c18 --- /dev/null +++ b/src/YUILoader.h @@ -0,0 +1,164 @@ +/* + Copyright (C) 2000-2017 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUILoader.h + + Author: Stefan Hundhammer + +/-*/ + + +#ifndef YUILoader_h +#define YUILoader_h + + +#include + +#include "YUI.h" +#include "YExternalWidgets.h" + + + +#define YUIPlugin_Qt "qt" +#define YUIPlugin_NCurses "ncurses" +#define YUIPlugin_Gtk "gtk" + + +/** + * Class to load one of the concrete UI plug-ins: Qt, NCurses, Gtk. + **/ +class YUILoader +{ +public: + /** + * Load any of the available UI-plugins by this order and criteria: + * + * - Qt: + * - if $DISPLAY is set + * - NCurses is user-selected and stdout is *not* a TTY + * + * - Gtk: + * - if $DISPLAY is set and Qt is not available, + * - a GTK-based desktop environment is detected + * from the environment variable XDG_CURRENT_DESKTOP + * - any of the above pre-conditions are met and + * NCurses is user-selected, but stdout is *not* a TTY + * + * - NCurses: + * - if $DISPLAY is *not* set and stdout is a TTY + * - Qt and Gtk are not available and stdout is a TTY + * + * This can be overridden by either: + * + * - specifing one of the switches on the + * command-line of the program + * - '--gtk', + * - '--ncurses', or + * - '--qt' + * + * - setting the environment variable + * YUI_PREFERED_BACKEND to one of + * - 'gtk', + * - 'ncurses', or + * - 'qt' + * + * If a command-line switch is given to the program, the + * setting from the environment variable will be overridden + * by the UI-plugin chosen with the switch. + * + * If the user-selected UI-plugin is not installed on the + * system, an installed UI-plugin will be chosen by the + * above criteria. + **/ + static void loadUI( bool withThreads = false ); + + /** + * This will make sure the UI singleton is deleted. + * If the UI is already destroyed, it will do nothing. If + * there still is a UI object, it will be deleted. + * + * This is particularly important for the NCurses UI so that + * the terminal settings are properly restored. + **/ + static void deleteUI(); + + /** + * Load a UI plug-in. 'name' is one of the YUIPlugin_ -defines above. + * + * This might throw exceptions. + **/ + static void loadPlugin( const std::string & name, bool withThreads = false ); + + static bool pluginExists( const std::string & pluginBaseName ); + + /** + * Load the given External Widgets plugin followed by its graphical extension implementation + * in the following order in the same way as loadUI: + * - Qt, Gtk or NCurses + * + * 'name' is the user defined plugin name, graphical extension implementations have to + * be called 'name'-qt, 'name'-gtk and 'name'-ncurses. Following this rule plugin + * file names are as libyui-XX-YY.so.VER where: + * XX is the user defined name + * YY is the UI used (ncurses, gtk, qt) + * VER is the libyui so version + * 'symbol' is the function symbol to be loaded, e.g. YExternalWidgets* 'symbol'(void) + * (e.g. default YExternalWidgets* createExternalWidgets(const char *) + * see createEWFunction_t definition) + **/ + static void loadExternalWidgets( const std::string & name, const std::string & symbol="_Z21createExternalWidgetsPKc" ); + +private: + YUILoader() {} + ~YUILoader() {} + + /** + * Used by loadExternalWidgets to load the graphical plugin specialization. + * + * 'name' is the original plugin name (e.g. the one passed to loadExternalWidgets) + * 'plugin_name' is the graphical plugin specialization name (e.g. 'name'-[gtk|ncurses|qt]) + * 'symbol' is the function symbol to be loaded and executed (e.g. the one passed loadExternalWidgets) + * This might throw exceptions: + * YUIPluginException if the plugin has not been loaded + * specific exception can be thrown by funtion invoked (param symbol) + **/ + static void loadExternalWidgetsPlugin( const std::string& name, const std::string& plugin_name, const std::string& symbol ); +}; + + +/** + * Every UI plug-in has to provide a function + * + * YUI * createUI( bool withThreads ) + * + * that creates a UI of that specific type upon the first call and returns that + * singleton for all subsequent calls. + **/ +typedef YUI * (*createUIFunction_t)( bool ); + +/** + * Every EW extension plug-in has to provide a function + * + * YExternalWidgets * createEW( ) + * + * that creates a EW of that specific type upon the first call and returns that + * singleton for all subsequent calls. + **/ +typedef YExternalWidgets * (*createEWFunction_t)( const char * ); + +#endif // YUILoader_h diff --git a/src/YUILog.cc b/src/YUILog.cc new file mode 100644 index 0000000..c510347 --- /dev/null +++ b/src/YUILog.cc @@ -0,0 +1,568 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUILog.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include + +#include +#include +#include +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUIException.h" + + +static void stdLogger( YUILogLevel_t logLevel, + const char * logComponent, + const char * sourceFileName, + int sourceLineNo, + const char * sourceFunctionName, + const char * message ); + +static std::ostream * stdLogStream = &std::cerr; + + +/** + * Stream buffer class that will use the YUILog's logger function. + * + * See also http://blogs.awesomeplay.com/elanthis/archives/2007/12/10/ + **/ +class YUILogBuffer: public std::streambuf +{ + friend class YUILog; + +public: + + /** + * Constructor. + **/ + YUILogBuffer() + : logComponent( 0 ) + , sourceFileName( 0 ) + , lineNo( 0 ) + , functionName( 0 ) + {} + + /** + * Destructor. + **/ + virtual ~YUILogBuffer() + { flush(); } + + /** + * Write (no more than maxLength characters of) a sequence of characters + * and return the number of characters written. + * + * Reimplemented from std::streambuf. + * This is called for all output operations on the associated ostream. + **/ + virtual std::streamsize xsputn( const char * sequence, std::streamsize maxLength ); + + /** + * Write one character in case of buffer overflow. + * + * Reimplemented from std::streambuf. + **/ + virtual int overflow( int ch = EOF ); + + /** + * Write (no more than maxLength characters of) a sequence of characters + * and return the number of characters written. + * + * This is the actual worker function that uses the YUILog::loggerFunction to + * actually write characters. + **/ + std::streamsize writeBuffer( const char * sequence, std::streamsize seqLen ); + + /** + * Flush the output buffer: Write any data unwritten so far. + **/ + void flush(); + + +private: + + YUILogLevel_t logLevel; + const char * logComponent; + const char * sourceFileName; + int lineNo; + const char * functionName; + + std::string buffer; +}; + + + +std::streamsize +YUILogBuffer::writeBuffer( const char * sequence, std::streamsize seqLen ) +{ + // Add new character sequence + + if ( seqLen > 0 ) + buffer += std::string( sequence, seqLen ); + + // + // Output buffer contents line by line + // + + std::size_t start = 0; + std::size_t newline_pos = 0; + + while ( start < buffer.length() && + ( newline_pos = buffer.find_first_of( '\n', start ) ) != std::string::npos ) + { + YUILoggerFunction loggerFunction = YUILog::loggerFunction( true ); // never return 0 + + std::string line = buffer.substr( start, newline_pos - start ); + + loggerFunction( logLevel, logComponent, + YUILog::basename( sourceFileName ).c_str(), lineNo, functionName, + line.c_str() ); + + start = newline_pos + 1; + } + + if ( start < buffer.length() ) + buffer = buffer.substr( start, std::string::npos ); + else + buffer.clear(); + + return seqLen; +} + + +std::streamsize +YUILogBuffer::xsputn( const char * sequence, std::streamsize maxLength ) +{ + return writeBuffer( sequence, maxLength ); +} + + +int +YUILogBuffer::overflow( int ch ) +{ + if ( ch != EOF ) + { + char sequence = ch; + writeBuffer( &sequence, 1 ); + } + + return 0; +} + + +void YUILogBuffer::flush() +{ + writeBuffer( "\n", 1 ); +} + + + + + +/** + * Helper class: Per-thread logging information. + * + * Multiple threads can easily clobber each others' half-done logging. + * A naive approach to prevent this would be to lock a mutex when a thread + * starts logging and unlock it when it's done logging. But that "when it's + * done" condition might never come true. std::endl or a newline in the output + * stream would be one indication, but there is no way to make sure there + * always is such a delimiter. If it is forgotten and that thread (that still + * has the mutex locked) runs into a waiting condition itself (e.g., UI thread + * synchronization with pipes), there would be a deadlock. + * + * So this much safer approach was chosen: Give each thread its own logging + * infrastructure, i.e., its own log stream and its own log buffer. + * + * Sure, in bad cases the logger function might still be executed in parallel + * and thus clobber a line or two of log output. But that's merely bad output + * formatting, not writing another thread's data structures without control - + * which can easily happen if multiple threads are working on the same output + * buffer, i.e. manipulate the same string. + **/ +struct YPerThreadLogInfo +{ + /** + * Constructor + **/ + YPerThreadLogInfo() + : threadHandle( pthread_self() ) + , logBuffer() + , logStream( &logBuffer ) + { + // std::cerr << "New thread with ID " << hex << threadHandle << dec << std::endl; + } + + /** + * Destructor + **/ + ~YPerThreadLogInfo() + { + logBuffer.flush(); + } + + /** + * Check if this per-thread logging information belongs to the specified thread. + **/ + bool isThread( pthread_t otherThreadHandle ) + { + return pthread_equal( otherThreadHandle, this->threadHandle ); + } + + + // + // Data members + // + + pthread_t threadHandle; + YUILogBuffer logBuffer; + std::ostream logStream; +}; + + + + +struct YUILogPrivate +{ + /** + * Constructor + **/ + YUILogPrivate() + : loggerFunction( stdLogger ) + , enableDebugLoggingHook( 0 ) + , debugLoggingEnabledHook( 0 ) + , enableDebugLogging( false ) + {} + + /** + * Destructor + **/ + ~YUILogPrivate() + { + for ( unsigned i=0; i < threadLogInfo.size(); i++ ) + delete threadLogInfo[i]; + } + + /** + * Find the per-thread logging information for the current thread. + * Create a new one if it doesn't exist yet. + **/ + YPerThreadLogInfo * findCurrentThread() + { + pthread_t thisThread = pthread_self(); + + // Search backwards: Slight optimization for the UI. + // The UI thread does the most logging, but it is created after the + // main thread. + + for ( std::vector::reverse_iterator it = threadLogInfo.rbegin(); + it != threadLogInfo.rend(); + ++it ) + { + if ( (*it)->isThread( thisThread ) ) + return (*it); + } + + YPerThreadLogInfo * newThreadLogInfo = new YPerThreadLogInfo(); + threadLogInfo.push_back( newThreadLogInfo ); + + return newThreadLogInfo; + } + + // + // Data members + // + + std::string logFileName; + std::ofstream stdLogStream; + YUILoggerFunction loggerFunction; + YUIEnableDebugLoggingFunction enableDebugLoggingHook; + YUIDebugLoggingEnabledFunction debugLoggingEnabledHook; + bool enableDebugLogging; + + std::vector threadLogInfo; +}; + + + + +YUILog::YUILog() + : priv( new YUILogPrivate() ) +{ + YUI_CHECK_NEW( priv ); +} + + +YUILog::~YUILog() +{ + if ( priv->stdLogStream.is_open() ) + priv->stdLogStream.close(); +} + + +YUILog * +YUILog::instance() +{ + static YUILog * instance = 0; + + if ( ! instance ) + { + instance = new YUILog(); + YUI_CHECK_NEW( instance ); + } + + return instance; +} + + +bool +YUILog::setLogFileName( const std::string & logFileName ) +{ + instance()->priv->logFileName = logFileName; + + std::ofstream & logStream = instance()->priv->stdLogStream; + + if ( logStream.is_open() ) + logStream.close(); + + bool success = true; + + if ( logFileName.empty() ) // log to stderr again + { + stdLogStream = &std::cerr; + } + else + { + logStream.open( logFileName.c_str(), std::ios_base::app ); + success = logStream.good(); + + if ( success ) + { + stdLogStream = &( instance()->priv->stdLogStream ); + } + else + { + std::cerr << "ERROR: Can't open log file " << logFileName << std::endl; + stdLogStream = &std::cerr; + } + } + + return success; +} + + +std::string +YUILog::logFileName() +{ + return instance()->priv->logFileName; +} + + +void +YUILog::enableDebugLogging( bool debugLogging ) +{ + instance()->priv->enableDebugLogging = debugLogging; + + if ( instance()->priv->enableDebugLoggingHook ) + instance()->priv->enableDebugLoggingHook( debugLogging ); +} + + +bool +YUILog::debugLoggingEnabled() +{ + if ( instance()->priv->debugLoggingEnabledHook ) + return instance()->priv->debugLoggingEnabledHook(); + else + return instance()->priv->enableDebugLogging; +} + + +void +YUILog::setLoggerFunction( YUILoggerFunction loggerFunction ) +{ + if ( ! loggerFunction ) + loggerFunction = stdLogger; + + instance()->priv->loggerFunction = loggerFunction; +} + + +YUILoggerFunction +YUILog::loggerFunction( bool returnStdLogger ) +{ + YUILoggerFunction logger = instance()->priv->loggerFunction; + + if ( logger == stdLogger && ! returnStdLogger ) + logger = 0; + + return logger; +} + + +void +YUILog::setEnableDebugLoggingHooks( YUIEnableDebugLoggingFunction enableFunction, + YUIDebugLoggingEnabledFunction isEnabledFunction ) +{ + instance()->priv->enableDebugLoggingHook = enableFunction; + instance()->priv->debugLoggingEnabledHook = isEnabledFunction; +} + + +YUIEnableDebugLoggingFunction +YUILog::enableDebugLoggingHook() +{ + return instance()->priv->enableDebugLoggingHook; +} + + +YUIDebugLoggingEnabledFunction +YUILog::debugLoggingEnabledHook() +{ + return instance()->priv->debugLoggingEnabledHook; +} + + +std::ostream & +YUILog::log( YUILogLevel_t logLevel, + const char * logComponent, + const char * sourceFileName, + int lineNo, + const char * functionName ) +{ + YPerThreadLogInfo * threadLogInfo = priv->findCurrentThread(); + + if ( ! threadLogInfo->logBuffer.buffer.empty() ) // Leftovers from previous logging? + { + if ( threadLogInfo->logBuffer.logLevel != logLevel || + threadLogInfo->logBuffer.lineNo != lineNo || + strcmp( threadLogInfo->logBuffer.logComponent, logComponent ) != 0 || + strcmp( threadLogInfo->logBuffer.sourceFileName, sourceFileName ) != 0 || + strcmp( threadLogInfo->logBuffer.functionName, functionName ) != 0 ) + { + threadLogInfo->logBuffer.flush(); + } + } + + threadLogInfo->logBuffer.logLevel = logLevel; + threadLogInfo->logBuffer.logComponent = logComponent; + threadLogInfo->logBuffer.sourceFileName = sourceFileName; + threadLogInfo->logBuffer.lineNo = lineNo; + threadLogInfo->logBuffer.functionName = functionName; + + return threadLogInfo->logStream; +} + + +std::ostream & +YUILog::debug( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ) +{ + return instance()->log( YUI_LOG_DEBUG, logComponent, sourceFileName, lineNo, functionName ); +} + + +std::ostream & +YUILog::milestone( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ) +{ + return instance()->log( YUI_LOG_MILESTONE, logComponent, sourceFileName, lineNo, functionName ); +} + + +std::ostream & +YUILog::warning( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ) +{ + return instance()->log( YUI_LOG_WARNING, logComponent, sourceFileName, lineNo, functionName ); +} + + +std::ostream & +YUILog::error( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ) +{ + return instance()->log( YUI_LOG_ERROR, logComponent, sourceFileName, lineNo, functionName ); +} + + + +std::string +YUILog::basename( const std::string & fileNameWithPath ) +{ + std::size_t lastSlashPos = fileNameWithPath.find_last_of( '/' ); + + std::string fileName = + ( lastSlashPos == std::string::npos ) ? + fileNameWithPath : + fileNameWithPath.substr( lastSlashPos+1 ); + + return fileName; +} + + + +static void +stdLogger( YUILogLevel_t logLevel, + const char * logComponent, + const char * sourceFileName, + int sourceLineNo, + const char * sourceFunctionName, + const char * message ) +{ + const char * logLevelStr = ""; + + switch ( logLevel ) + { + case YUI_LOG_DEBUG: + if ( ! YUILog::debugLoggingEnabled() ) + return; + + logLevelStr = "dbg"; + break; + + case YUI_LOG_MILESTONE: logLevelStr = "_M_"; break; + case YUI_LOG_WARNING: logLevelStr = "WRN"; break; + case YUI_LOG_ERROR: logLevelStr = "ERR"; break; + } + + if ( ! logComponent ) + logComponent = "??"; + + if ( ! sourceFileName ) + sourceFileName = "??"; + + if ( ! sourceFunctionName ) + sourceFunctionName = "??"; + + if ( ! message ) + message = ""; + + (*stdLogStream) << "<" << logLevelStr << "> " + << "[" << logComponent << "] " + << sourceFileName << ":" << sourceLineNo << " " + << sourceFunctionName << "(): " + << message + << std::endl; +} diff --git a/src/YUILog.h b/src/YUILog.h new file mode 100644 index 0000000..0890bc5 --- /dev/null +++ b/src/YUILog.h @@ -0,0 +1,240 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUILog.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YUILog_h + +#ifndef YUILogComponent +#error Missing #define YUILogComponent "myComponent" before #include "YUILog.h" +#endif + +#include +#include + +#include "ImplPtr.h" + + +// +// UI Logging: Macros for Application use. +// +// They all return a std::ostream & for use with operator<<(). +// #define YUILogComponent before including this header file +// to identify what subsystem ("my-ui" etc.) this log line belongs to. +// +// #define YUILogComponent "myComponent" +// #include +// +// ... +// yuiDebug() << "Creating widget" << widget << std::endl; +// yuiError() << "No widget with ID " << id << std::endl; +// +// Unless the underlying logger function handles this differently, +// Milestone, Warning and Error are always logged, Debug only when enabled. +// + +#define yuiDebug() YUILog::debug ( YUILogComponent, __FILE__, __LINE__, __FUNCTION__ ) +#define yuiMilestone() YUILog::milestone( YUILogComponent, __FILE__, __LINE__, __FUNCTION__ ) +#define yuiWarning() YUILog::warning ( YUILogComponent, __FILE__, __LINE__, __FUNCTION__ ) +#define yuiError() YUILog::error ( YUILogComponent, __FILE__, __LINE__, __FUNCTION__ ) + + +// +// ------ End of user relevant part ------ +// + + + +class YUILogPrivate; + +enum YUILogLevel_t +{ + YUI_LOG_DEBUG = 0, + YUI_LOG_MILESTONE, + YUI_LOG_WARNING, + YUI_LOG_ERROR +}; + + +/** + * Logger function. + * + * All const char pointer parameters might be 0. + **/ +typedef void (*YUILoggerFunction)( YUILogLevel_t, // logLevel + const char *, // logComponent + const char *, // sourceFileName + int, // sourceLineNo + const char *, // sourceFunctionName + const char * ); // message + +typedef void (*YUIEnableDebugLoggingFunction)( bool ); +typedef bool (*YUIDebugLoggingEnabledFunction)(); + + +/** + * UI logging. + **/ +class YUILog +{ +public: + + /** + * Logging functions for each log level. They all access the singleton object for this class. + * This means that the first call to any of those functions will create the singleton YUILog object. + **/ + static std::ostream & debug ( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ); + static std::ostream & milestone( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ); + static std::ostream & warning ( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ); + static std::ostream & error ( const char * logComponent, const char * sourceFileName, int lineNo, const char * functionName ); + + /** + * Generic log function. debug(), milestone() etc. ultimately all call this function. + **/ + std::ostream & log( YUILogLevel_t logLevel, + const char * logComponent, + const char * sourceFileName, + int lineNo, + const char * functionName ); + + /** + * Return the singleton object for this class. + * This will create the singleton if it doesn't exist yet. + **/ + static YUILog * instance(); + + /** + * Enable or disable debug logging. + **/ + static void enableDebugLogging( bool debugLogging = true ); + + /** + * Return 'true' if debug logging is enabled, 'false' if not. + **/ + static bool debugLoggingEnabled(); + + /** + * Set the log file name to be used with the standard logger function. + * Output will be appended to this file. + * + * Until this file name is set, the standard logger function logs to stderr. + * Set the log file name to an empty string to log to stderr again. + * + * This returns 'true' upon success (opening the file was successful), + *'false' upon error. + * + * + * Notice: + * + * (1) This file name is only relevant as long as the standard logger + * function is used. Custom logger functions may or may not use this + * file name. + * + * (2) No attempt is made to do anything fancy with the log file like log + * file rotation when a certain file size is reached. Applications that + * need this should use a custom logger function. + * See also setLoggerFunction(). + **/ + static bool setLogFileName( const std::string & logFileName ); + + /** + * Return the current log file name or an empty string if stderr is used. + * Notice that this information is only relevant as long as the standard + * logger function is used. + **/ + static std::string logFileName(); + + /** + * Set the UI logger function. This is the function that will ultimately + * receive all UI log output (except debug logging if debug logging is + * disabled). + * + * By default, all logging is output to stderr. This behaviour can be + * restored if 0 is passed as a function pointer here. + **/ + static void setLoggerFunction( YUILoggerFunction loggerFunction ); + + /** + * Return the UI logger function. + * + * If stderr is used for logging (i.e. no logger function set), 0 is + * returned (unless 'returnStdLogger' is 'true', in which case the + * internally used stderr-logger is returned). + **/ + static YUILoggerFunction loggerFunction( bool returnStdLogger = false ); + + /** + * Set the hook functions to enable/disable debug logging and to query if + * debug logging is enabled: + * + * void enableDebugLogging( bool enable ); + * bool debugLoggingEnabled(); + * + * If those functions are set, they will be used instead of the internal + * "debugLogging" flag. + **/ + static void setEnableDebugLoggingHooks( YUIEnableDebugLoggingFunction enableFunction, + YUIDebugLoggingEnabledFunction isEnabledFunction ); + + /** + * Return the hook function that enables or disables debug logging + * or 0 if no such hook function is set. + **/ + static YUIEnableDebugLoggingFunction enableDebugLoggingHook(); + + /** + * Return the hook function that checks if debug logging is enabled + * or 0 if no such hook function is set. + **/ + static YUIDebugLoggingEnabledFunction debugLoggingEnabledHook(); + + /** + * Return the base name without path from a file name with path. + **/ + static std::string basename( const std::string & fileNameWithPath ); + + +private: + /** + * Constructor. + * + * Not for application use - use one of the static functions above instead. + * They all access the singleton object for this class. + **/ + YUILog(); + + /** + * Destructor. + **/ + ~YUILog(); + + // + // Data + // + + ImplPtr priv; +}; + + +#define YUILog_h + +#endif // YUILog_h diff --git a/src/YUIPlugin.cc b/src/YUIPlugin.cc new file mode 100644 index 0000000..769b5e9 --- /dev/null +++ b/src/YUIPlugin.cc @@ -0,0 +1,119 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUIPlugin.h + + Author: Stefan Hundhammer + +/-*/ + + +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUIPlugin.h" +#include "YPath.h" + +#include "Libyui_config.h" + + +YUIPlugin::YUIPlugin( const char * pluginLibBaseName ) +{ + _pluginLibBaseName = std::string( pluginLibBaseName ); + + std::string pluginFilename = pluginLibFullPath(); + + _pluginLibHandle = dlopen( pluginFilename.c_str(), + RTLD_NOW | RTLD_GLOBAL); + + if ( ! _pluginLibHandle ) + { + _errorMsg = dlerror(); + + yuiError() << "Could not load UI plugin \"" << pluginLibBaseName + << "\": " << _errorMsg + << std::endl; + } +} + + +YUIPlugin::~YUIPlugin() +{ + // This intentionally does NOT call unload(): This would be + // counterproductive for almost all use cases of this class. +} + + +void +YUIPlugin::unload() +{ + if ( _pluginLibHandle ) + dlclose( _pluginLibHandle ); +} + + +std::string +YUIPlugin::pluginLibFullPath() const +{ + + std::string pluginName = PLUGIN_PREFIX; + pluginName.append( _pluginLibBaseName ); + pluginName.append( PLUGIN_SUFFIX ); + + YPath plugin( PLUGINDIR, pluginName ); + + return plugin.path(); +} + + +void * YUIPlugin::locateSymbol( const char * symbol ) +{ + if ( ! _pluginLibHandle ) + return 0; + + void * addr = dlsym( _pluginLibHandle, symbol ); + + if ( ! addr ) + { + yuiError() << "Could not locate symbol \"" << symbol + << "\" in " << pluginLibFullPath() + << std::endl; + } + + return addr; +} + + +bool YUIPlugin::error() const +{ + return _pluginLibHandle == 0; +} + + +bool YUIPlugin::success() const +{ + return _pluginLibHandle != 0; +} + + +std::string YUIPlugin::errorMsg() const +{ + return _errorMsg; +} diff --git a/src/YUIPlugin.h b/src/YUIPlugin.h new file mode 100644 index 0000000..aac1217 --- /dev/null +++ b/src/YUIPlugin.h @@ -0,0 +1,111 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUIPlugin.h + + Author: Stefan Hundhammer + +/-*/ + + +#ifndef YUIPlugin_h +#define YUIPlugin_h + +#include + + +/** + * Wrapper class for dlopen() and related. + **/ +class YUIPlugin +{ +public: + + /** + * Constructor: Load the specified plugin library + * from the standard UI plugin directory (/usr/lib/yui/). + **/ + YUIPlugin( const char * pluginLibBaseName ); + + /** + * Destructor. + * + * Please note that this will NOT attempt to unload the plugin library + * since this is usually counterproductive. If unloading the plugin is + * desired, call unload() manually. + **/ + virtual ~YUIPlugin(); + + /** + * Unload this plugin. This calls dlclose() which will unload the plugin + * library if it is no longer used, i.e. if the reference count dlopen() + * uses reaches 0. + **/ + void unload(); + + /** + * Try to locate the specified symbol (function or global variable) in the + * plugin library. + * + * Returns the in-memory address of that symbol or 0 if it could not be + * found or if loading the plugin library had failed in the constructor. + **/ + void * locateSymbol( const char * symbol ); + + /** + * Returns 'true' if there was an error loading the plugin. + **/ + bool error() const; + + /** + * Returns 'true' if there was no error loading the plugin. + **/ + bool success() const; + + /** + * Returns a human readable (but in most cases untranslated) error message + * if there was an error. + **/ + std::string errorMsg() const; + +protected: + + /** + * Returns the dlopen() handle of the plugin library. + **/ + void * pluginLibHandle() { return _pluginLibHandle; } + + /** + * Returns the base name of the plugin library. + **/ + std::string pluginLibBaseName() const { return _pluginLibBaseName; } + + /** + * Returns the full path of the plugin library. + **/ + std::string pluginLibFullPath() const; + +private: + + std::string _pluginLibBaseName; + void * _pluginLibHandle; + std::string _errorMsg; +}; + + +#endif // YUIPlugin_h diff --git a/src/YUISymbols.h b/src/YUISymbols.h new file mode 100644 index 0000000..8b80635 --- /dev/null +++ b/src/YUISymbols.h @@ -0,0 +1,345 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YUISymbols.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YUISymbols_h +#define YUISymbols_h + + +// UI builtin functions + +#define YUIBuiltin_AskForExistingDirectory "AskForExistingDirectory" +#define YUIBuiltin_AskForExistingFile "AskForExistingFile" +#define YUIBuiltin_AskForSaveFileName "AskForSaveFileName" +#define YUIBuiltin_Beep "Beep" +#define YUIBuiltin_BusyCursor "BusyCursor" +#define YUIBuiltin_OpenContextMenu "OpenContextMenu" +#define YUIBuiltin_ChangeWidget "ChangeWidget" +#define YUIBuiltin_CloseDialog "CloseDialog" +#define YUIBuiltin_CloseUI "CloseUI" +#define YUIBuiltin_DumpWidgetTree "DumpWidgetTree" +#define YUIBuiltin_GetDisplayInfo "GetDisplayInfo" +#define YUIBuiltin_GetLanguage "GetLanguage" +#define YUIBuiltin_GetProductName "GetProductName" +#define YUIBuiltin_Glyph "Glyph" +#define YUIBuiltin_HasSpecialWidget "HasSpecialWidget" +#define YUIBuiltin_MakeScreenShot "MakeScreenShot" +#define YUIBuiltin_NormalCursor "NormalCursor" +#define YUIBuiltin_OpenDialog "OpenDialog" +#define YUIBuiltin_OpenUI "OpenUI" +#define YUIBuiltin_PollInput "PollInput" +#define YUIBuiltin_QueryWidget "QueryWidget" +#define YUIBuiltin_RecalcLayout "RecalcLayout" +#define YUIBuiltin_Recode "Recode" +#define YUIBuiltin_RedrawScreen "RedrawScreen" +#define YUIBuiltin_ReplaceWidget "ReplaceWidget" +#define YUIBuiltin_RunPkgSelection "RunPkgSelection" +#define YUIBuiltin_SetConsoleFont "SetConsoleFont" +#define YUIBuiltin_SetFocus "SetFocus" +#define YUIBuiltin_SetFunctionKeys "SetFunctionKeys" +#define YUIBuiltin_SetKeyboard "SetKeyboard" +#define YUIBuiltin_RunInTerminal "RunInTerminal" +#define YUIBuiltin_SetLanguage "SetLanguage" +#define YUIBuiltin_SetProductName "SetProductName" +#define YUIBuiltin_TimeoutUserInput "TimeoutUserInput" +#define YUIBuiltin_UserInput "UserInput" +#define YUIBuiltin_WaitForEvent "WaitForEvent" +#define YUIBuiltin_WidgetExists "WidgetExists" +#define YUIBuiltin_WizardCommand "WizardCommand" + +#define YUIBuiltin_PostponeShortcutCheck "PostponeShortcutCheck" +#define YUIBuiltin_CheckShortcuts "CheckShortcuts" + +#define YUIBuiltin_RecordMacro "RecordMacro" +#define YUIBuiltin_StopRecordMacro "StopRecordMacro" +#define YUIBuiltin_PlayMacro "PlayMacro" +#define YUIBuiltin_FakeUserInput "FakeUserInput" +#define YUIBuiltin_WFM "WFM" +#define YUIBuiltin_SCR "SCR" + + + +// Mandatory widgets + +#define YUIWidget_Bottom "Bottom" +#define YUIWidget_BusyIndicator "BusyIndicator" +#define YUIWidget_ButtonBox "ButtonBox" +#define YUIWidget_CheckBox "CheckBox" +#define YUIWidget_CheckBoxFrame "CheckBoxFrame" +#define YUIWidget_ComboBox "ComboBox" +#define YUIWidget_Empty "Empty" +#define YUIWidget_Frame "Frame" +#define YUIWidget_HBox "HBox" +#define YUIWidget_HCenter "HCenter" +#define YUIWidget_HSpacing "HSpacing" +#define YUIWidget_HSquash "HSquash" +#define YUIWidget_HStretch "HStretch" +#define YUIWidget_HVCenter "HVCenter" +#define YUIWidget_HVSquash "HVSquash" +#define YUIWidget_HWeight "HWeight" +#define YUIWidget_Heading "Heading" +#define YUIWidget_IconButton "IconButton" +#define YUIWidget_Image "Image" +#define YUIWidget_InputField "InputField" +#define YUIWidget_IntField "IntField" +#define YUIWidget_Label "Label" +#define YUIWidget_Left "Left" +#define YUIWidget_LogView "LogView" +#define YUIWidget_MarginBox "MarginBox" +#define YUIWidget_MenuButton "MenuButton" +#define YUIWidget_MinHeight "MinHeight" +#define YUIWidget_MinSize "MinSize" +#define YUIWidget_MinWidth "MinWidth" +#define YUIWidget_MultiLineEdit "MultiLineEdit" +#define YUIWidget_MultiSelectionBox "MultiSelectionBox" +#define YUIWidget_PackageSelector "PackageSelector" +#define YUIWidget_Password "Password" +#define YUIWidget_PkgSpecial "PkgSpecial" +#define YUIWidget_ProgressBar "ProgressBar" +#define YUIWidget_PushButton "PushButton" +#define YUIWidget_RadioButton "RadioButton" +#define YUIWidget_RadioButtonGroup "RadioButtonGroup" +#define YUIWidget_ReplacePoint "ReplacePoint" +#define YUIWidget_RichText "RichText" +#define YUIWidget_Right "Right" +#define YUIWidget_SelectionBox "SelectionBox" +#define YUIWidget_Table "Table" +#define YUIWidget_TextEntry "TextEntry" // for backwards compatibility +#define YUIWidget_Top "Top" +#define YUIWidget_Tree "Tree" +#define YUIWidget_VBox "VBox" +#define YUIWidget_VCenter "VCenter" +#define YUIWidget_VSpacing "VSpacing" +#define YUIWidget_VSquash "VSquash" +#define YUIWidget_VStretch "VStretch" +#define YUIWidget_VWeight "VWeight" + + +// Special (optional) widgets + +#define YUISpecialWidget_BarGraph "BarGraph" +#define YUISpecialWidget_Date "Date" +#define YUISpecialWidget_DateField "DateField" +#define YUISpecialWidget_DownloadProgress "DownloadProgress" +#define YUISpecialWidget_DumbTab "DumbTab" +#define YUISpecialWidget_DummySpecialWidget "DummySpecialWidget" +#define YUISpecialWidget_HMultiProgressMeter "HMultiProgressMeter" +#define YUISpecialWidget_VMultiProgressMeter "VMultiProgressMeter" +#define YUISpecialWidget_PartitionSplitter "PartitionSplitter" +#define YUISpecialWidget_PatternSelector "PatternSelector" +#define YUISpecialWidget_SimplePatchSelector "SimplePatchSelector" +#define YUISpecialWidget_Slider "Slider" +#define YUISpecialWidget_Time "Time" +#define YUISpecialWidget_TimeField "TimeField" +#define YUISpecialWidget_Wizard "Wizard" +#define YUISpecialWidget_TimezoneSelector "TimezoneSelector" +#define YUISpecialWidget_Graph "Graph" +#define YUISpecialWidget_ContextMenu "ContextMenu" + + +// Widget properties + +#define YUIProperty_Alive "Alive" +#define YUIProperty_Cell "Cell" +#define YUIProperty_ContextMenu "ContextMenu" +#define YUIProperty_CurrentBranch "CurrentBranch" +#define YUIProperty_CurrentButton "CurrentButton" +#define YUIProperty_CurrentItem "CurrentItem" +#define YUIProperty_CurrentSize "CurrentSize" +#define YUIProperty_DebugLabel "DebugLabel" +#define YUIProperty_EasterEgg "EasterEgg" +#define YUIProperty_Enabled "Enabled" +#define YUIProperty_ExpectedSize "ExpectedSize" +#define YUIProperty_Filename "Filename" +#define YUIProperty_Layout "Layout" +#define YUIProperty_HelpText "HelpText" +#define YUIProperty_IconPath "IconPath" +#define YUIProperty_InputMaxLength "InputMaxLength" +#define YUIProperty_HWeight "HWeight" +#define YUIProperty_HStretch "HStretch" +#define YUIProperty_ID "ID" +#define YUIProperty_Item "Item" +#define YUIProperty_Items "Items" +#define YUIProperty_Label "Label" +#define YUIProperty_Labels "Labels" +#define YUIProperty_LastLine "LastLine" +#define YUIProperty_MaxLines "MaxLines" +#define YUIProperty_MaxValue "MaxValue" +#define YUIProperty_MinValue "MinValue" +#define YUIProperty_MultiSelection "MultiSelection" +#define YUIProperty_Notify "Notify" +#define YUIProperty_OpenItems "OpenItems" +#define YUIProperty_SelectedItems "SelectedItems" +#define YUIProperty_Text "Text" +#define YUIProperty_Timeout "Timeout" +#define YUIProperty_ValidChars "ValidChars" +#define YUIProperty_Value "Value" +#define YUIProperty_Values "Values" +#define YUIProperty_VisibleLines "VisibleLines" +#define YUIProperty_VWeight "VWeight" +#define YUIProperty_VStretch "VStretch" +#define YUIProperty_WidgetClass "WidgetClass" + + +// Widget and dialog options + +#define YUIOpt_animated "animated" +#define YUIOpt_applyButton "applyButton" +#define YUIOpt_autoScrollDown "autoScrollDown" +#define YUIOpt_autoShortcut "autoShortcut" +#define YUIOpt_boldFont "boldFont" +#define YUIOpt_cancelButton "cancelButton" +#define YUIOpt_centered "centered" +#define YUIOpt_confirmUnsupported "confirmUnsupported" +#define YUIOpt_customButton "customButton" +#define YUIOpt_debugLayout "debugLayout" +#define YUIOpt_decorated "decorated" +#define YUIOpt_default "default" +#define YUIOpt_defaultsize "defaultsize" +#define YUIOpt_disabled "disabled" +#define YUIOpt_easterEgg "easterEgg" +#define YUIOpt_editable "editable" +#define YUIOpt_helpButton "helpButton" +#define YUIOpt_relNotesButton "relNotesButton" +#define YUIOpt_hstretch "hstretch" +#define YUIOpt_hvstretch "hvstretch" +#define YUIOpt_immediate "immediate" +#define YUIOpt_infocolor "infocolor" +#define YUIOpt_invertAutoEnable "invertAutoEnable" +#define YUIOpt_keepSorting "keepSorting" +#define YUIOpt_keyEvents "keyEvents" +#define YUIOpt_mainDialog "mainDialog" +#define YUIOpt_multiSelection "multiSelection" +#define YUIOpt_noAutoEnable "noAutoEnable" +#define YUIOpt_notify "notify" +#define YUIOpt_notifyContextMenu "notifyContextMenu" +#define YUIOpt_okButton "okButton" +#define YUIOpt_outputField "outputField" +#define YUIOpt_plainText "plainText" +#define YUIOpt_recursiveSelection "recursiveSelection" +#define YUIOpt_relaxSanityCheck "relaxSanityCheck" +#define YUIOpt_repoMgr "repoMgr" +#define YUIOpt_repoMode "repoMode" +#define YUIOpt_scaleToFit "scaleToFit" +#define YUIOpt_searchMode "searchMode" +#define YUIOpt_shrinkable "shrinkable" +#define YUIOpt_stepsEnabled "stepsEnabled" +#define YUIOpt_summaryMode "summaryMode" +#define YUIOpt_testMode "testMode" +#define YUIOpt_tiled "tiled" +#define YUIOpt_titleOnLeft "titleOnLeft" +#define YUIOpt_treeEnabled "treeEnabled" +#define YUIOpt_updateMode "updateMode" +#define YUIOpt_vstretch "vstretch" +#define YUIOpt_warncolor "warncolor" +#define YUIOpt_wizardDialog "wizardDialog" +#define YUIOpt_youMode "youMode" +#define YUIOpt_zeroHeight "zeroHeight" +#define YUIOpt_zeroWidth "zeroWidth" + +#define YUIOpt_key_F1 "key_F1" +#define YUIOpt_key_F2 "key_F2" +#define YUIOpt_key_F3 "key_F3" +#define YUIOpt_key_F4 "key_F4" +#define YUIOpt_key_F5 "key_F5" +#define YUIOpt_key_F6 "key_F6" +#define YUIOpt_key_F7 "key_F7" +#define YUIOpt_key_F8 "key_F8" +#define YUIOpt_key_F9 "key_F9" +#define YUIOpt_key_F10 "key_F10" +#define YUIOpt_key_F11 "key_F11" +#define YUIOpt_key_F12 "key_F12" +#define YUIOpt_key_F13 "key_F13" +#define YUIOpt_key_F14 "key_F14" +#define YUIOpt_key_F15 "key_F15" +#define YUIOpt_key_F16 "key_F16" +#define YUIOpt_key_F17 "key_F17" +#define YUIOpt_key_F18 "key_F18" +#define YUIOpt_key_F19 "key_F19" +#define YUIOpt_key_F20 "key_F20" +#define YUIOpt_key_F21 "key_F21" +#define YUIOpt_key_F22 "key_F22" +#define YUIOpt_key_F23 "key_F23" +#define YUIOpt_key_F24 "key_F24" +#define YUIOpt_key_none "key_none" + + +// Predefined glyphs for builtin Glyph() +// +// - remember there must be a substitute that can be displayed in plain ASCII, +// so don't include just everything here that is included in Unicode / UTF-8! + +#define YUIGlyph_ArrowLeft "ArrowLeft" +#define YUIGlyph_ArrowRight "ArrowRight" +#define YUIGlyph_ArrowUp "ArrowUp" +#define YUIGlyph_ArrowDown "ArrowDown" + +#define YUIGlyph_CheckMark "CheckMark" +#define YUIGlyph_BulletArrowRight "BulletArrowRight" +#define YUIGlyph_BulletCircle "BulletCircle" +#define YUIGlyph_BulletSquare "BulletSquare" + + + +// Display capabilities for GetDisplayInfo() + +#define YUICap_Width "Width" +#define YUICap_Height "Height" +#define YUICap_Depth "Depth" +#define YUICap_Colors "Colors" +#define YUICap_DefaultWidth "DefaultWidth" +#define YUICap_DefaultHeight "DefaultHeight" +#define YUICap_TextMode "TextMode" +#define YUICap_HasImageSupport "HasImageSupport" +#define YUICap_HasAnimationSupport "HasAnimationSupport" +#define YUICap_HasIconSupport "HasIconSupport" +#define YUICap_HasFullUtf8Support "HasFullUtf8Support" +#define YUICap_HasWizardDialogSupport "HasWizardDialogSupport" +#define YUICap_RichTextSupportsTable "RichTextSupportsTable" +#define YUICap_LeftHandedMouse "LeftHandedMouse" +#define YUICap_y2debug "y2debug" + + + +// Misc + +#define YUISymbol_id "id" +#define YUISymbol_opt "opt" +#define YUISymbol_icon "icon" +#define YUISymbol_item "item" +#define YUISymbol_cell "cell" +#define YUISymbol_menu "menu" +#define YUISymbol_header "header" +#define YUISymbol_rgb "rgb" +#define YUISymbol_leftMargin "leftMargin" +#define YUISymbol_rightMargin "rightMargin" +#define YUISymbol_topMargin "topMargin" +#define YUISymbol_bottomMargin "bottomMargin" +#define YUISymbol_BackgroundPixmap "BackgroundPixmap" + +#define YUISymbol_Left "Left" +#define YUISymbol_Right "Right" +#define YUISymbol_Center "Center" + + +#endif // YUISymbols_h diff --git a/src/YWidget.cc b/src/YWidget.cc new file mode 100644 index 0000000..e8beed1 --- /dev/null +++ b/src/YWidget.cc @@ -0,0 +1,789 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWidget.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include +#include +#include + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YUISymbols.h" +#include "YShortcut.h" +#include "YWidget.h" +#include "YDialog.h" +#include "YUI.h" +#include "YDialog.h" +#include "YUIException.h" +#include "YWidgetID.h" +#include "YBothDim.h" +#include "YMacroRecorder.h" + +#include "YChildrenManager.h" + +#define MAX_DEBUG_LABEL_LEN 50 +#define YWIDGET_MAGIC 42 + +#define CHECK_FOR_DUPLICATE_CHILDREN 1 +#define LOG_WIDGET_REP 0 + + + +struct YWidgetPrivate +{ + /** + * Constructor + **/ + YWidgetPrivate( YWidgetChildrenManager * manager, YWidget * parentWidget = 0 ) + : childrenManager( manager ) + , parent( parentWidget ) + , beingDestroyed( false ) + , enabled( true ) + , notify( false ) + , notifyContextMenu( false ) + , sendKeyEvents( false ) + , autoShortcut( false ) + , toolkitWidgetRep( 0 ) + , id( 0 ) + , functionKey( 0 ) + { + stretch.hor = false; + stretch.vert = false; + weight.hor = 0; + weight.vert = 0; + } + + // + // Data members + // + + YWidgetChildrenManager * childrenManager; + YWidget * parent; + bool beingDestroyed; + bool enabled; + bool notify; + bool notifyContextMenu; + bool sendKeyEvents; + bool autoShortcut; + void * toolkitWidgetRep; + YWidgetID * id; + YBothDim stretch; + YBothDim weight; + int functionKey; + std::string helpText; +}; + + + + +bool YWidget::_usedOperatorNew = false; + + +YWidget::YWidget( YWidget * parent ) + : _magic( YWIDGET_MAGIC ) + , priv( new YWidgetPrivate( new YWidgetChildrenRejector( this ), parent ) ) +{ + YUI_CHECK_NEW( priv ); + YUI_CHECK_NEW( priv->childrenManager ); + + if ( ! _usedOperatorNew ) + { + yuiError() << "FATAL: Widget at " + << std::hex << (void *) this << std::dec + << " not created with operator new !" + << std::endl; + yuiError() << "Check core dump for a backtrace." << std::endl; + abort(); + } + + _usedOperatorNew = false; + + if ( parent ) + parent->addChild( this ); +} + + +void * YWidget::operator new( size_t size ) +{ + _usedOperatorNew = true; + return ::operator new( size ); +} + + +YWidget::~YWidget() +{ + YUI_CHECK_WIDGET( this ); + setBeingDestroyed(); + // yuiDebug() << "Destructor of YWidget " << this << std::endl; + + deleteChildren(); + YUI::ui()->deleteNotify( this ); + + if ( parent() && ! parent()->beingDestroyed() ) + parent()->removeChild( this ); + + delete priv->childrenManager; + + if ( priv->id ) + delete priv->id; + + invalidate(); +} + + +YWidgetChildrenManager * +YWidget::childrenManager() const +{ + return priv->childrenManager; +} + + +void +YWidget::setChildrenManager( YWidgetChildrenManager * newChildrenManager ) +{ + YUI_CHECK_PTR( newChildrenManager ); + + delete priv->childrenManager; + priv->childrenManager = newChildrenManager; +} + + +void +YWidget::addChild( YWidget * child ) +{ +#if CHECK_FOR_DUPLICATE_CHILDREN + if ( child && childrenManager()->contains( child ) ) + { + yuiError() << this << " already contains " << child << std::endl; + YUI_THROW( YUIInvalidChildException( this, child ) ); + } +#endif + + childrenManager()->add( child ); +} + + +void +YWidget::removeChild( YWidget * child ) +{ + if ( ! beingDestroyed() ) + { + // yuiDebug() << "Removing " << child << " from " << this << std::endl; + childrenManager()->remove( child ); + } +} + + +void +YWidget::deleteChildren() +{ + YWidgetList::const_iterator it = childrenBegin(); + + while ( it != childrenEnd() ) + { + YWidget * child = *it; + ++it; + + if ( child->isValid() ) + { + // yuiDebug() << "Deleting " << child << std::endl; + delete child; + } + } + + childrenManager()->clear(); +} + + +std::string +YWidget::debugLabel() const +{ + std::string label = YShortcut::cleanShortcutString( YShortcut::getShortcutString( this ) ); + + if ( label.size() > MAX_DEBUG_LABEL_LEN ) + { + label.resize( MAX_DEBUG_LABEL_LEN ); + label.append( "..." ); + } + + for ( unsigned i=0; i < label.size(); i++ ) + { + if ( label[i] == '\n' ) + label[i] = ' '; + } + + return label; +} + + +bool +YWidget::isValid() const +{ + return _magic == YWIDGET_MAGIC; +} + + +void +YWidget::invalidate() +{ + _magic = 0; +} + + +bool +YWidget::beingDestroyed() const +{ + return priv->beingDestroyed; +} + +void +YWidget::setBeingDestroyed() +{ + priv->beingDestroyed = true; +} + + +YWidget * +YWidget::parent() const +{ + return priv->parent; +} + + +bool +YWidget::hasParent() const +{ + return priv->parent; +} + + +void +YWidget::setParent( YWidget * newParent ) +{ + if ( newParent && priv->parent ) + { + YDialog::currentDialog()->dumpWidgetTree(); + yuiWarning() << "Reparenting " << this + << " from " << priv->parent + << " to " << newParent << std::endl; + YUI_THROW( YUIException( std::string( widgetClass() ) + " already has a parent!" ) ); + } + + priv->parent = newParent; +} + + +bool YWidget::sendKeyEvents() const +{ + return priv->sendKeyEvents; +} + + +void YWidget::setSendKeyEvents( bool doSend ) +{ + priv->sendKeyEvents = doSend; +} + + +bool YWidget::autoShortcut() const +{ + return priv->autoShortcut; +} + + +void YWidget::setAutoShortcut( bool newAutoShortcut ) +{ + priv->autoShortcut = newAutoShortcut; +} + + +int YWidget::functionKey() const +{ + return priv->functionKey; +} + + +bool YWidget::hasFunctionKey() const +{ + return priv->functionKey > 0; +} + + +void YWidget::setFunctionKey( int fkey_no ) +{ + priv->functionKey = fkey_no; +} + + +std::string YWidget::helpText() const +{ + return priv->helpText; +} + + +void YWidget::setHelpText( const std::string & helpText ) +{ + priv->helpText = helpText; +} + + +YWidgetID * +YWidget::id() const +{ + return priv->id; +} + + +void YWidget::setId( YWidgetID * newId ) +{ + if ( priv->id ) + delete priv->id; + + priv->id = newId; +} + + +bool YWidget::hasId() const +{ + return priv->id != 0; +} + + +YDialog * YWidget::findDialog() +{ + YWidget * widget = this; + + while ( widget ) + { + YDialog * dialog = dynamic_cast (widget); + + if ( dialog ) + return dialog; + else + widget = widget->parent(); + } + + return 0; +} + + +const YPropertySet & +YWidget::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /** + * @property boolean Enabled enabled/disabled state of this widget + * @property boolean Notify the current notify state (see also `opt( `notify )) + * @property boolean ContextMenu the current contextmenu state (see also `opt( `notifyContextMenu )) + * @property std::string WidgetClass the widget class of this widget (YLabel, YPushButton, ...) + * @property std::string DebugLabel (possibly translated) text describing this widget for debugging + * @property std::string ID widget id as a read-only property + * @property std::string HelpText help text + * @property integer HWeight horizontal layout weight (same as `HWeight(widget()) + * @property integer VWeight vertical layout weight (same as `VWeight(widget()) + * @property boolean HStretch horizontally stretchable? (same as `opt(`hstretch)) + * @property boolean VStretch vertically stretchable? (same as `opt(`vstretch)) + **/ + + propSet.add( YProperty( YUIProperty_Enabled, YBoolProperty ) ); + propSet.add( YProperty( YUIProperty_Notify, YBoolProperty ) ); + propSet.add( YProperty( YUIProperty_WidgetClass, YStringProperty, true ) ); // read-only + propSet.add( YProperty( YUIProperty_DebugLabel, YStringProperty, true ) ); // read-only + propSet.add( YProperty( YUIProperty_ID, YStringProperty, true ) ); // read-only + propSet.add( YProperty( YUIProperty_HelpText, YStringProperty ) ); + propSet.add( YProperty( YUIProperty_HWeight, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_VWeight, YIntegerProperty ) ); + propSet.add( YProperty( YUIProperty_HStretch, YBoolProperty ) ); + propSet.add( YProperty( YUIProperty_VStretch, YBoolProperty ) ); + } + + return propSet; +} + + +bool +YWidget::setProperty( const std::string & propertyName, const YPropertyValue & val ) +{ + try + { + propertySet().check( propertyName, val.type() ); // throws exceptions if not found or type mismatch + } + catch( YUIPropertyException & exception ) + { + exception.setWidget( this ); + throw; + } + + if ( propertyName == YUIProperty_Enabled ) setEnabled( val.boolVal() ); + else if ( propertyName == YUIProperty_Notify ) setNotify ( val.boolVal() ); + else if ( propertyName == YUIProperty_HelpText ) setHelpText( val.stringVal() ); + else if ( propertyName == YUIProperty_HWeight ) setWeight( YD_HORIZ, val.integerVal() ); + else if ( propertyName == YUIProperty_VWeight ) setWeight( YD_VERT , val.integerVal() ); + else if ( propertyName == YUIProperty_HStretch ) setStretchable( YD_HORIZ, val.boolVal() ); + else if ( propertyName == YUIProperty_VStretch ) setStretchable( YD_VERT , val.boolVal() ); + + return true; // success -- no special processing necessary +} + + +YPropertyValue +YWidget::getProperty( const std::string & propertyName ) +{ + try + { + propertySet().check( propertyName ); // throws exceptions if not found + } + catch( YUIPropertyException & exception ) + { + exception.setWidget( this ); + throw; + } + + if ( propertyName == YUIProperty_Enabled ) return YPropertyValue( isEnabled() ); + if ( propertyName == YUIProperty_Notify ) return YPropertyValue( notify() ); + if ( propertyName == YUIProperty_ContextMenu ) return YPropertyValue( notifyContextMenu() ); + if ( propertyName == YUIProperty_WidgetClass ) return YPropertyValue( widgetClass() ); + if ( propertyName == YUIProperty_HelpText ) return YPropertyValue( helpText() ); + if ( propertyName == YUIProperty_DebugLabel ) return YPropertyValue( debugLabel() ); + if ( propertyName == YUIProperty_HWeight ) return YPropertyValue( weight( YD_HORIZ ) ); + if ( propertyName == YUIProperty_VWeight ) return YPropertyValue( weight( YD_VERT ) ); + if ( propertyName == YUIProperty_HStretch ) return YPropertyValue( stretchable( YD_HORIZ ) ); + if ( propertyName == YUIProperty_VStretch ) return YPropertyValue( stretchable( YD_VERT ) ); + if ( propertyName == YUIProperty_ID && this->hasId() ) return YPropertyValue(this->id()->toString()); + + return YPropertyValue( false ); // NOTREACHED +} + + +void * +YWidget::widgetRep() const +{ + return priv->toolkitWidgetRep; +} + + +void +YWidget::setWidgetRep( void * rep ) +{ + priv->toolkitWidgetRep = rep; +} + + +void +YWidget::setEnabled( bool enabled ) +{ + priv->enabled = enabled; +} + + +bool +YWidget::isEnabled() const +{ + return priv->enabled; +} + + +void YWidget::setShortcutString( const std::string & str ) +{ + yuiError() << "Default setShortcutString() method called - " + << "this should be reimplemented in " + << widgetClass() + << std::endl; +} + + +void YWidget::setNotify( bool notify ) +{ + priv->notify = notify; +} + + +void YWidget::setNotifyContextMenu( bool notifyContextMenu ) +{ + priv->notifyContextMenu = notifyContextMenu; +} + + +bool YWidget::notify() const +{ + return priv->notify; +} + + +bool YWidget::notifyContextMenu() const +{ + return priv->notifyContextMenu; +} + + +int YWidget::preferredSize( YUIDimension dim ) +{ + switch ( dim ) + { + case YD_HORIZ: return preferredWidth(); + case YD_VERT : return preferredHeight(); + + default: + YUI_THROW( YUIInvalidDimensionException() ); + return 0; + } +} + + +void YWidget::setStretchable( YUIDimension dim, bool newStretch ) +{ + priv->stretch[ dim ] = newStretch; +} + + +void YWidget::setDefaultStretchable( YUIDimension dim, bool newStretch ) +{ + priv->stretch[ dim ] |= newStretch; +} + + +bool YWidget::stretchable( YUIDimension dim ) const +{ + return priv->stretch[ dim ]; +} + + +int YWidget::weight( YUIDimension dim ) +{ + return priv->weight[ dim ]; +} + + +void YWidget::setWeight( YUIDimension dim, int weight ) +{ + priv->weight[ dim ] = weight; +} + + +bool YWidget::hasWeight( YUIDimension dim ) +{ + // DO NOT simply return priv->weight[ dim ] here + // since weight() might be overwritten in derived classes! + + return weight( dim ) > 0; +} + + +bool YWidget::setKeyboardFocus() +{ + yuiWarning() << this << " cannot accept the keyboard focus." << std::endl; + return false; +} + + +YWidget * +YWidget::findWidget( YWidgetID * id, bool doThrow ) const +{ + if ( ! id ) + { + if ( doThrow ) + YUI_THROW( YUIWidgetNotFoundException( "Null ID" ) ); + + return 0; + } + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YWidget * child = *it; + YUI_CHECK_WIDGET( child ); + + if ( child->id() && child->id()->isEqual( id ) ) + return child; + + if ( child->hasChildren() ) + { + YWidget * found = child->findWidget( id, false ); + + if ( found ) + return found; + } + } + + if ( doThrow ) + YUI_THROW( YUIWidgetNotFoundException( id->toString() ) ); + + return 0; +} + + +void YWidget::setChildrenEnabled( bool enabled ) +{ + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YWidget * child = *it; + + if ( child->hasChildren() ) + { + // yuiDebug() << "Recursing into " << child << std::endl; + child->setChildrenEnabled( enabled ); + } + + // yuiDebug() << ( enabled ? "Enabling " : "Disabling " ) << child << std::endl; + child->setEnabled( enabled ); + } +} + + +void YWidget::dumpDialogWidgetTree() +{ + YWidget * dialog = findDialog(); + + if ( dialog ) + dialog->dumpWidgetTree(); + else + dumpWidgetTree(); +} + + +void YWidget::dumpWidgetTree( int indentationLevel ) +{ + dumpWidget( this, indentationLevel ); + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YWidget * child = *it; + + if ( child->hasChildren() ) + child->dumpWidgetTree ( indentationLevel + 1 ); + else + dumpWidget( child, indentationLevel + 1 ); + } +} + + +void YWidget::dumpWidget( YWidget *w, int indentationLevel ) +{ + std::ostringstream str; + + std::string indentation ( indentationLevel * 4, ' ' ); + str << "Widget tree: " << indentation << w; + + if ( w->widgetRep() ) + { + str << " (widgetRep: " + << std::hex << w->widgetRep() << std::dec + << ")"; + } + + std::string stretch; + + if ( w->stretchable( YD_HORIZ ) ) stretch += "hstretch "; + if ( w->stretchable( YD_VERT ) ) stretch += "vstretch"; + + if ( ! stretch.empty() ) + str << " ( " << stretch << " ) "; + + yuiMilestone() << str.str() << std::endl; +} + + +void +YWidget::saveUserInput( YMacroRecorder *macroRecorder ) +{ + // + // Record this widget's user input property (if there is any) + // + + if ( userInputProperty() ) + { + macroRecorder->recordWidgetProperty( this, userInputProperty() ); + } + + // + // Record the child widgets' (if there are any) user input + // + + for ( YWidgetListConstIterator it = childrenBegin(); + it != childrenEnd(); + ++it ) + { + YWidget *widget = *it; + + if ( widget->hasChildren() || widget->hasId() ) + { + /* + * It wouldn't do any good to save the user input of any widget + * that doesn't have an ID since this ID is required to make use of + * this saved data later when playing the macro. + * Other than that, container widgets need to recurse over all + * their children. + */ + + widget->saveUserInput( macroRecorder ); + } + } +} + + +std::ostream & operator<<( std::ostream & stream, const YWidget * w ) +{ + if ( w ) + { + stream << w->widgetClass(); + + std::string debugLabel = w->debugLabel(); + + if ( debugLabel.empty() ) + { + if ( w->hasId() ) + stream << " ID: \"" << w->id() << "\""; + } + else // Has debugLabel + { + stream << " \"" << debugLabel << "\""; + } + + stream << " at " << std::hex << (void *) w << std::dec; + +#if LOG_WIDGET_REP + if ( w->widgetRep() ) + { + stream << " (widgetRep: " + << std::hex << w->widgetRep() << std::dec + << ")"; + } +#endif + } + else + { + stream << ""; + } + + return stream; +} diff --git a/src/YWidget.h b/src/YWidget.h new file mode 100644 index 0000000..5b285d0 --- /dev/null +++ b/src/YWidget.h @@ -0,0 +1,720 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWidget.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YWidget_h +#define YWidget_h + +#include +#include + +#include "YTypes.h" +#include "YProperty.h" +#include "YUISymbols.h" +#include "YUIException.h" +#include "YChildrenManager.h" +#include "ImplPtr.h" + + +class YDialog; +class YWidgetID; +class YMacroRecorder; + + +typedef YChildrenManager YWidgetChildrenManager; +typedef YSingleChildManager YSingleWidgetChildManager; +typedef YChildrenRejector YWidgetChildrenRejector; + +class YWidgetPrivate; + + +/** + * Abstract base class of all UI widgets + **/ +class YWidget +{ +protected: + /** + * Constructor. + **/ + YWidget( YWidget * parent ); + +public: + /** + * Destructor. + **/ + virtual ~YWidget(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YWidget"; } + + /** + * Returns a descriptive label of this widget instance. + * + * This default implementation returns this widget's "shortcut property" + * (possibly trunctated to avoid over-long texts) - the property that + * contains the keyboard shortcut used to activate this widget or to move + * the keyboard focus to it. In most cases this is this widget's label. + * + * Note: This is usually translated to the user's target language. + * This makes this useful for debugging only. + **/ + virtual std::string debugLabel() const; + + /** + * Return the help text for this widget. + **/ + std::string helpText() const; + + /** + * Set a help text for this widget. + * + * Currently, the UI does not do anything with this text but store it. + * Displaying the text at a convenient time is currently the application's + * responsibility. This may change in future versions. + **/ + void setHelpText( const std::string & helpText ); + + + // + // Property Management + // + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Derived classes should reimplement this. + * + * Remember to add the base class's property set to your own + * in reimplemented versions, e.g.: + * + * const YPropertySet & + * MyWidgetClass::propertySet() + * { + * static YPropertySet propSet; + * + * if ( propSet.isEmpty() ) + * { + * // Add properties for the derived class + * propSet.add( YProperty( YUIProperty_Value, YStringProperty ) ); + * propSet.add( YProperty( YUIProperty_Label, YStringProperty ) ); + * + * // Add base class properties + * propSet.add( YWidget::propertySet() ); + * } + * + * return propSet; + * } + * + * Otherwise the base class's properties will not be available in the + * derived class. It is also important that the base class's properties + * are added after those of the derived class so the derived class's + * properties have priority over those of the base class. + **/ + virtual const YPropertySet & propertySet(); + + /** + * Set a property. Derived classes need to implement this. + * + * This method may throw exceptions, for example + * - if there is no property with that name + * - if the expected type and the type mismatch + * - if the value is out of range + * + * This function returns 'true' if the value was successfully set and + * 'false' if that value requires special handling (not in error cases: + * those are covered by exceptions). + **/ + virtual bool setProperty( const std::string & propertyName, + const YPropertyValue & val ); + + /** + * Get a property. Derived classes need to implement this. + * + * This method may throw exceptions, for example + * - if there is no property with that name + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + + // + // Children Management + // + // Even though many widget classes are leaf classes and thus cannot have + // children by design, it makes sense to have the children management in + // this base class: Then descending down a widget tree is transparent to + // the outside without the need to check for container widget classes, + // casting to those container widget classes and only calling child + // management methods in that case. + // + // By default, YWidget and derived classes have a YWidgetChildrenRejector + // as their children manager, i.e. any attempt to add a child will result + // in a YUITooManyChildrenException. + // + // Derived classes that can (semantically) handle children should set the + // children manager to one of + // + // - YWidgetChildrenManager: handles any number of child widgets; + // useful for VBox / HBox + // + // - YSingleWidgetChildManager: handles exactly one child + // useful for widgets like Alignment, Frame, Dialog + // + + + /** + * Returns 'true' if this widget has any children. + **/ + bool hasChildren() const + { return childrenManager()->hasChildren(); } + + /** + * Returns the first child or 0 if there is none. + * Useful mostly for children managers that handle only one child. + **/ + YWidget * firstChild() const + { return childrenManager()->firstChild(); } + + /** + * Returns the last child or 0 if there is none. + **/ + YWidget * lastChild() const + { return childrenManager()->lastChild(); } + + /** + * Return an iterator that points to the first child or to childrenEnd() if + * there are no children. + **/ + YWidgetListIterator childrenBegin() const + { return childrenManager()->begin(); } + + /** + * Return an interator that points after the last child. + **/ + YWidgetListIterator childrenEnd() const + { return childrenManager()->end(); } + + /** + * Return a const iterator that points to the first child or to childrenEnd() if + * there are no children. + **/ + YWidgetListConstIterator childrenConstBegin() const + { return childrenManager()->begin(); } + + /** + * Return a const interator that points after the last child. + **/ + YWidgetListConstIterator childrenConstEnd() const + { return childrenManager()->end(); } + + /** + * A helper for the range-based "for" loop + * @return Iterator pointing to the beginning of the children list + */ + YWidgetListIterator begin() + { return childrenBegin(); } + + /** + * A helper for the range-based "for" loop + * @return Iterator pointing to the end of the children list + */ + YWidgetListIterator end() + { return childrenEnd(); } + + /** + * Returns the current number of children. + **/ + int childrenCount() const { return childrenManager()->count(); } + + /** + * Checks if 'child' is a (direct!) child of this widget. + **/ + bool contains( YWidget * child ) const + { return childrenManager()->contains( child ); } + + /** + * Add a new child. + * + * This may throw exceptions if more children are added than this widget + * can handle. + **/ + virtual void addChild( YWidget * child ); + + /** + * Remove a child. This only removes the child from the children manager's + * list; it does not delete it. + **/ + virtual void removeChild( YWidget * child ); + + /** + * Delete all children and remove them from the children manager's list. + **/ + void deleteChildren(); + + /** + * Return this widget's parent or 0 if it doesn't have a parent. + **/ + YWidget * parent() const; + + /** + * Return 'true' if this widget has a parent, 'false' if not. + **/ + bool hasParent() const; + + /** + * Set this widget's parent. + **/ + void setParent( YWidget * newParent ); + + /** + * Traverse up the widget hierarchy and find the dialog this widget belongs + * to. Returns 0 if there is none. + **/ + YDialog * findDialog(); + + /** + * Recursively find a widget by its ID. + * If there is no widget with that ID, this function throws a + * YUIWidgetNotFoundException if 'doThrow' is 'true'. It returns 0 if + * 'doThrow' is 'false'. + **/ + YWidget * findWidget( YWidgetID * id, bool doThrow = true ) const; + + + // + // Geometry Management + // + + /** + * Preferred width of the widget. + * + * Derived classes are required to implement this. + **/ + virtual int preferredWidth() = 0; + + /** + * Preferred height of the widget. + * + * Derived classes are required to implement this. + **/ + virtual int preferredHeight() = 0; + + /** + * Preferred size of the widget in the specified dimension. + * This default implementation calls preferredWidth() or preferredHeight() + * which makes sense for most cases. + * + * Derived classes can reimplement this, but this is discouraged. + * + * Note: Even in that case, preferredWidth() and preferredHeight() need to + * be implemented, but they might then call preferredSize(). + **/ + virtual int preferredSize( YUIDimension dim ); + + /** + * Set the new size of the widget. + * + * Layout manager widgets (like YLayoutBox) call this during geometry + * management after all widgets are queried about their preferred widths + * and heights. Depending on layout constraints, widgets might be resized + * beyond or below their preferred size. + * + * The sizes passed here are not meant to affect any future + * preferredWidth() or preferredHeight() calls; they are just the outcome + * of all kinds of compromises (too little screen space or too much) for + * the current geometry management calculation. + * + * Derived classes are required to implement this function. + **/ + virtual void setSize( int newWidth, int newHeight ) = 0; + + + // + // Misc + // + + + /** + * Checks whether or not this object is valid. This is to enable + * dangling pointer error checking (i.e. this object is already + * deallocated, but a pointer to it is still in use). + * + * See also the YUI_CHECK_WIDGET() macro in YUIException.h + **/ + bool isValid() const; + + /** + * Check if this widget is in the process of being destroyed. + **/ + bool beingDestroyed() const; + + /** + * Return a pointer to the underlying toolkit's (Qt, ...) widget + * representing this abstract UI widget. + **/ + void * widgetRep() const; + + /** + * Set the pointer to the underlying toolkit's (Qt, ...) widget + * representing this abstract UI widget. + * + * This pointer might be useful for derived UIs to store a counterpart of + * the toolkit widget in each YWidget. The abstract UI does not need that, + * though; this is purely for the convenience of derived UIs. All the + * abstract UI ever does with that pointer is store it. + **/ + void setWidgetRep( void * toolkitWidgetRep ); + + /** + * Returns 'true' if this widget has an ID. + **/ + bool hasId() const; + + /** + * Returns this widget's ID. + **/ + YWidgetID * id() const; + + /** + * Set this widget's ID. + * + * The widget assumes ownership of this ID and will delete it when needed. + * (In the widget's destructor or when a new ID is set) + * + * Widget IDs are purely for application use. C++ applications don't need + * to use them; they are much better off using widget pointers. For other + * languages, though, that can't use C++ pointers (e.g. Ruby) it makes + * sense to have widget IDs to identify widgets. + **/ + void setId( YWidgetID * newId_disown ); + + /** + * Enable or disable this widget, i.e. make it accept or reject user input. + * + * Derived classes should call the base class method to update the internal + *"enabled" flag. + **/ + virtual void setEnabled( bool enabled = true ); + + /** + * Disable this widget (overloaded for better readability). + **/ + void setDisabled() { setEnabled( false); } + + /** + * Returns 'true' if this widget is enabled. + **/ + virtual bool isEnabled() const; + + /** + * This is a boolean value that determines whether the widget is resizable + * beyond its preferred size in the specified dimension. A selection box is + * stretchable in both dimensions, a push button is not stretchable by + * default, a frame is stretchable if its contents are stretchable. Most + * widgets accept a `hstretch or `vstretch option to become stretchable + * even when by default they are not. + **/ + virtual bool stretchable( YUIDimension dim ) const; + + /** + * Set the stretchable state to "newStretch" regardless of any `hstretch or + * `vstretch options. + **/ + void setStretchable( YUIDimension dim, bool newStretch ); + + /** + * Set the stretchable state to "newStretch". + * `hstretch or `vstretch options may override this. + **/ + void setDefaultStretchable( YUIDimension dim, bool newStretch ); + + /** + * The weight is used in situations where all widgets can get their + * preferred size and yet space is available. The remaining space will be + * devided between all stretchable widgets according to their weights. A + * widget with greater weight will get more space. The default weight for + * all widgets is 0. + * + * Derived classes can overwrite this function, but they should call this + * base class function in the new function. + **/ + virtual int weight( YUIDimension dim ); + + /** + * Return whether or not the widget has a weight in the specified + * dimension. + **/ + bool hasWeight( YUIDimension dim ); + + /** + * Set a weight in the specified dimension. + **/ + void setWeight( YUIDimension dim, int weight ); + + /** + * Sets the Notify property + **/ + void setNotify( bool notify = true ); + + /** + * Returns whether the widget will notify, i.e. will case UserInput to + * return. + **/ + bool notify() const; + + /** + * Sets the notifyContextMenu property + **/ + void setNotifyContextMenu( bool notifyContextMenu = true ); + + /** + * Returns whether the widget will send an event when the user + * clicks selects the context menu e.g. via right click. + **/ + bool notifyContextMenu() const; + + + /** + * Returns 'true' if this widget should send key events, i.e. if it has + * `opt(`keyEvent) set. + **/ + bool sendKeyEvents() const; + + /** + * Specify whether or not this widget should send key events. + **/ + void setSendKeyEvents( bool doSend ); + + /** + * Returns 'true' if a keyboard shortcut should automatically be assigned + * to this widget - without complaints in the log file. + **/ + bool autoShortcut() const; + + /** + * Sets the 'autoShortcut' flag. + **/ + void setAutoShortcut( bool _newAutoShortcut ); + + /** + * Return a function key number that is assigned to this widget. + * (1 for F1, 2 for F2, etc.; 0 for none) + **/ + int functionKey() const; + + /** + * Check if a function key is assigned to this widget. + **/ + bool hasFunctionKey() const; + + /** + * Assign a function key to this widget + * (1 for F1, 2 for F2, etc.; 0 for none) + * + * Derived classes may want to overwrite this function, but they should + * call this base class function in the new function. + **/ + virtual void setFunctionKey( int fkey_no ); + + /** + * Set the keyboard focus to this widget. + * The default implementation just emits a warning message. + * Overwrite this function for all widgets that can accept the + * keyboard focus. + * + * This function returns true if the widget did accept the + * keyboard focus, and false if not. + **/ + virtual bool setKeyboardFocus(); + + /** + * Get the string of this widget that holds the keyboard shortcut, if any. + * Most widgets will return label(). + * + * Overwrite this for widgets that can have keyboard shortcuts. + **/ + virtual std::string shortcutString() const { return std::string( "" ); } + + /** + * Set the string of this widget that holds the keyboard shortcut, if any. + * Most widgets will call setLabel(). + * + * Overwrite this for widgets that can have keyboard shortcuts. + **/ + virtual void setShortcutString( const std::string & str ); + + /** + * The name of the widget property that will return user input, if there is + * any. Widgets that do have user input (such as InputField, ComboBox, + * SelBox) should overwrite this methods. Widgets that are purely passive + * (such as Label, RichText) should not. + **/ + virtual const char * userInputProperty() { return (const char *) 0; } + + /** + * Debugging function: + * Dump the widget tree from here on to the log file. + **/ + void dumpWidgetTree( int indentationLevel = 0 ); + + /** + * Debugging function: + * Dump the widget tree from this widget's dialog parent. + * If there is no such dialog parent, dump the widget tree from + * here on. + **/ + void dumpDialogWidgetTree(); + + /** + * Enable or disable all widgets in this widget tree. + **/ + void setChildrenEnabled( bool enabled ); + + // + // Macro Recorder Support + // + + /** + * Recursively save the user input of all child widgets to a macro + * recorder: + * + * All child widgets that could contain data entered by the user + * are requested to send their contents to the macro recorder, e.g. input + * fields, check boxes etc. + * + * This default implementation records this widget's user input property + * (the property returned by userInputProperty) and then recursively calls + * saveUserInput() for all child widgets. This is suitable for most cases, + * for container widgets as well as for leaf widgets that have no or + * exactly one property that needs to be recorded. + * + * Widgets that need another number of properties recorded should + * reimplement this method (and NOT call this default method in the new + * implementation). + **/ + virtual void saveUserInput( YMacroRecorder *macroRecorder ); + + /** + * Overloaded operator new to ensure widgets are always created on the + * heap, never on the stack. + * + * Simpler implementations of this have a tendency to be fooled by poorly + * implemented derived classes. + **/ + void * operator new( size_t size ); + + + // NCurses optimizations + + + /** + * In some UIs updating the screen content is an expensive operation. Use + * startMultipleChanges() to tell the ui that you're going to perform + * multiple chages to the widget. The UI may delay any screen updates + * until doneMultipleChanges() is called. + **/ + virtual void startMultipleChanges() {} + virtual void doneMultipleChanges() {} + + +protected: + + /** + * Returns this widget's children manager. + **/ + YWidgetChildrenManager * childrenManager() const; + + /** + * Sets a new children manager for this widget. The widget assumes + * ownership of this children manager and will delete it when appropriate. + * + * The default children manager (a YWidgetChildrenRejector) rejects all + * children. This is useful for leaf widgets such as PushButton, ComboBox + * etc. + * + * Derived classes that can handle children might want to set the children + * manager to a YWidgetChildrenManager (the base class that does not reject + * children) or to a YSingleWidgetChildManager (the class that handles + * exactly one child widget). + **/ + void setChildrenManager( YWidgetChildrenManager * manager ); + + /** + * Set the "being destroyed" flag, i.e. indicate that this widget is in the + * process of being destroyed. The base class method already sets this, but + * sometimes it might be useful to call this in a derived class's + * destructor so certain optimizations work better. + * + * This status intentionally cannot be reverted to "not being destroyed". + **/ + void setBeingDestroyed(); + + /** + * Helper function for dumpWidgetTree(): + * Dump one widget to the log file. + **/ + void dumpWidget( YWidget *w, int indentationLevel ); + + +private: + + /** + * Make this widget invalid. This operation cannot be reversed. + **/ + void invalidate(); + + /** + * Disable copy constructor. + **/ + YWidget( const YWidget & other ); + + /** + * Disable assignment operator. + **/ + const YWidget & operator=( const YWidget & other ); + +private: + + // + // Data Members + // + + int _magic; // should always be the first member + ImplPtr priv; + static YPropertySet _propertySet; + static bool _usedOperatorNew; + + +#include "YWidget_OptimizeChanges.h" + +}; + + +std::ostream & operator<<( std::ostream & stream, const YWidget * widget ); + + +#endif // YWidget_h diff --git a/src/YWidgetFactory.cc b/src/YWidgetFactory.cc new file mode 100644 index 0000000..2d2aef9 --- /dev/null +++ b/src/YWidgetFactory.cc @@ -0,0 +1,272 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWidgetFactory.cc + + Author: Stefan Hundhammer + +/-*/ + +#include "YWidgetFactory.h" +#include "YAlignment.h" +#include "YPushButton.h" +#include "YUI.h" +#include "YApplication.h" + +#define YUILogComponent "wf" +#include "YUILog.h" + +YWidgetFactory::YWidgetFactory() +{ + // NOP +} + +YWidgetFactory::~YWidgetFactory() +{ + // NOP + yuiMilestone() << "YWidgetFactory removed" << std::endl; +} + + +YDialog * +YWidgetFactory::createMainDialog( YDialogColorMode colorMode ) +{ + return createDialog( YMainDialog, colorMode ); +} + + +YDialog * +YWidgetFactory::createPopupDialog( YDialogColorMode colorMode ) +{ + return createDialog( YPopupDialog, colorMode ); +} + + +YLayoutBox * +YWidgetFactory::createVBox( YWidget * parent ) +{ + return createLayoutBox( parent, YD_VERT ); +} + + +YLayoutBox * +YWidgetFactory::createHBox( YWidget * parent ) +{ + return createLayoutBox( parent, YD_HORIZ ); +} + + +YSpacing * +YWidgetFactory::createHStretch( YWidget * parent ) +{ + return createSpacing( parent, + YD_HORIZ, + true ); // stretchable +} + + +YSpacing * +YWidgetFactory::createVStretch( YWidget * parent ) +{ + return createSpacing( parent, + YD_VERT, + true ); // stretchable +} + + +YSpacing * +YWidgetFactory::createHSpacing( YWidget * parent, YLayoutSize_t size ) +{ + return createSpacing( parent, + YD_HORIZ, + false, // not stretchable + size ); +} + + +YSpacing * +YWidgetFactory::createVSpacing( YWidget * parent, YLayoutSize_t size ) +{ + return createSpacing( parent, + YD_VERT, + false, // not stretchable + size ); +} + + +YAlignment * +YWidgetFactory::createLeft( YWidget * parent ) +{ + return createAlignment( parent, YAlignBegin, YAlignUnchanged ); +} + + +YAlignment * +YWidgetFactory::createRight( YWidget * parent ) +{ + return createAlignment( parent, YAlignEnd, YAlignUnchanged ); +} + + +YAlignment * +YWidgetFactory::createTop( YWidget * parent ) +{ + return createAlignment( parent, YAlignUnchanged, YAlignBegin ); +} + + +YAlignment * +YWidgetFactory::createBottom( YWidget * parent ) +{ + return createAlignment( parent, YAlignUnchanged, YAlignEnd ); +} + + +YAlignment * +YWidgetFactory::createHCenter( YWidget * parent ) +{ + return createAlignment( parent, YAlignCenter, YAlignUnchanged ); +} + + +YAlignment * +YWidgetFactory::createVCenter( YWidget * parent ) +{ + return createAlignment( parent, YAlignUnchanged, YAlignCenter ); +} + + +YAlignment * +YWidgetFactory::createHVCenter( YWidget * parent ) +{ + return createAlignment( parent, YAlignCenter, YAlignCenter ); +} + + +YAlignment * +YWidgetFactory::createMarginBox( YWidget * parent, YLayoutSize_t horMargin, YLayoutSize_t vertMargin ) +{ + return createMarginBox( parent, + horMargin, horMargin, + vertMargin, vertMargin ); +} + + + +YAlignment * +YWidgetFactory::createMarginBox( YWidget * parent, + YLayoutSize_t leftMargin, YLayoutSize_t rightMargin, + YLayoutSize_t topMargin, YLayoutSize_t bottomMargin ) +{ + YAlignment * alignment = createAlignment( parent, YAlignUnchanged, YAlignUnchanged ); + + alignment->setLeftMargin ( YUI::app()->deviceUnits( YD_HORIZ, leftMargin ) ); + alignment->setRightMargin ( YUI::app()->deviceUnits( YD_HORIZ, rightMargin ) ); + alignment->setTopMargin ( YUI::app()->deviceUnits( YD_VERT, topMargin ) ); + alignment->setBottomMargin( YUI::app()->deviceUnits( YD_VERT, bottomMargin ) ); + + return alignment; +} + + +YAlignment * +YWidgetFactory::createMinWidth( YWidget * parent, YLayoutSize_t minWidth ) +{ + return createMinSize( parent, minWidth, 0 ); +} + + +YAlignment * +YWidgetFactory::createMinHeight( YWidget * parent, YLayoutSize_t minHeight ) +{ + return createMinSize( parent, 0, minHeight ); +} + + +YAlignment * +YWidgetFactory::createMinSize( YWidget * parent, YLayoutSize_t minWidth, YLayoutSize_t minHeight ) +{ + YAlignment * alignment = createAlignment( parent, YAlignUnchanged, YAlignUnchanged ); + + alignment->setMinWidth ( YUI::app()->deviceUnits( YD_HORIZ, minWidth ) ); + alignment->setMinHeight( YUI::app()->deviceUnits( YD_VERT, minHeight ) ); + + return alignment; +} + + +YSquash * +YWidgetFactory::createHSquash( YWidget * parent ) +{ + return createSquash( parent, true, false ); +} + + +YSquash * +YWidgetFactory::createVSquash( YWidget * parent ) +{ + return createSquash( parent, false, true ); +} + + +YSquash * +YWidgetFactory::createHVSquash( YWidget * parent ) +{ + return createSquash( parent, true, true ); +} + + +YPushButton * +YWidgetFactory::createIconButton( YWidget * parent, + const std::string & iconName, + const std::string & fallbackTextLabel ) +{ + YPushButton * button = createPushButton( parent, fallbackTextLabel ); + button->setIcon( iconName ); + + return button; +} + + +YLabel * +YWidgetFactory::createHeading( YWidget * parent, const std::string & text ) +{ + return createLabel( parent, + text, + true, // isHeading + false ); // isOutputField +} + + +YLabel * +YWidgetFactory::createOutputField( YWidget * parent, const std::string & text ) +{ + return createLabel( parent, + text, + false, // isHeading + true); // isOutputField +} + + +YInputField * +YWidgetFactory::createPasswordField( YWidget * parent, const std::string & label ) +{ + return createInputField( parent, + label, + true ); // passwordMode +} diff --git a/src/YWidgetFactory.h b/src/YWidgetFactory.h new file mode 100644 index 0000000..03c4925 --- /dev/null +++ b/src/YWidgetFactory.h @@ -0,0 +1,202 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWidgetFactory.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YWidgetFactory_h +#define YWidgetFactory_h + +#include + +#include "YTypes.h" + + +class YWidget; +class YAlignment; +class YButtonBox; +class YCheckBox; +class YCheckBoxFrame; +class YComboBox; +class YDialog; +class YEmpty; +class YFrame; +class YImage; +class YInputField; +class YIntField; +class YLabel; +class YLayoutBox; +class YLogView; +class YMenuButton; +class YMultiLineEdit; +class YMultiSelectionBox; +class YPackageSelector; +class YProgressBar; +class YPushButton; +class YRadioButton; +class YRadioButtonGroup; +class YReplacePoint; +class YRichText; +class YSelectionBox; +class YSpacing; +class YSquash; +class YTable; +class YTableHeader; +class YTimeField; +class YTree; +class YBusyIndicator; + + + +/** + * Abstract widget factory for mandatory widgets. + * Use YOptionalWidgetFactory for optional ("special") widgets. + * + * Refer to the respective widget's documentation (in the header file) for + * documentation about the function parameters. + **/ +class YWidgetFactory +{ +public: + + // + // Dialogs + // + + YDialog * createMainDialog ( YDialogColorMode colorMode = YDialogNormalColor ); + YDialog * createPopupDialog ( YDialogColorMode colorMode = YDialogNormalColor ); + virtual YDialog * createDialog ( YDialogType dialogType, YDialogColorMode colorMode = YDialogNormalColor ) = 0; + + // + // Layout Boxes + // + + YLayoutBox * createVBox ( YWidget * parent ); + YLayoutBox * createHBox ( YWidget * parent ); + virtual YLayoutBox * createLayoutBox ( YWidget * parent, YUIDimension dimension ) = 0; + virtual YButtonBox * createButtonBox ( YWidget * parent ) = 0; + + // + // Common Leaf Widgets + // + + virtual YPushButton * createPushButton ( YWidget * parent, const std::string & label ) = 0; + virtual YLabel * createLabel ( YWidget * parent, const std::string & text, bool isHeading = false, bool isOutputField = false ) = 0; + YLabel * createHeading ( YWidget * parent, const std::string & label ); + virtual YInputField * createInputField ( YWidget * parent, const std::string & label, bool passwordMode = false ) = 0; + virtual YCheckBox * createCheckBox ( YWidget * parent, const std::string & label, bool isChecked = false ) = 0; + virtual YRadioButton * createRadioButton ( YWidget * parent, const std::string & label, bool isChecked = false ) = 0; + virtual YComboBox * createComboBox ( YWidget * parent, const std::string & label, bool editable = false ) = 0; + virtual YSelectionBox * createSelectionBox ( YWidget * parent, const std::string & label ) = 0; + virtual YTree * createTree ( YWidget * parent, const std::string & label, bool multiselection = false, bool recursiveselection = false ) = 0; + virtual YTable * createTable ( YWidget * parent, YTableHeader * header_disown, bool multiSelection = false ) = 0; + virtual YProgressBar * createProgressBar ( YWidget * parent, const std::string & label, int maxValue = 100 ) = 0; + virtual YRichText * createRichText ( YWidget * parent, const std::string & text = std::string(), bool plainTextMode = false ) = 0; + virtual YBusyIndicator * createBusyIndicator ( YWidget * parent, const std::string & label, int timeout = 1000 ) = 0; + + // + // Less Common Leaf Widgets + // + + YPushButton * createIconButton ( YWidget * parent, const std::string & iconName, const std::string & fallbackTextLabel ); + YLabel * createOutputField ( YWidget * parent, const std::string & label ); + virtual YIntField * createIntField ( YWidget * parent, const std::string & label, int minVal, int maxVal, int initialVal ) = 0; + YInputField * createPasswordField ( YWidget * parent, const std::string & label ); + + virtual YMenuButton * createMenuButton ( YWidget * parent, const std::string & label ) = 0; + virtual YMultiLineEdit * createMultiLineEdit ( YWidget * parent, const std::string & label ) = 0; + virtual YImage * createImage ( YWidget * parent, const std::string & imageFileName, bool animated = false ) = 0; + virtual YLogView * createLogView ( YWidget * parent, const std::string & label, int visibleLines, int storedLines = 0 ) = 0; + virtual YMultiSelectionBox *createMultiSelectionBox ( YWidget * parent, const std::string & label ) = 0; + + virtual YPackageSelector * createPackageSelector ( YWidget * parent, long ModeFlags = 0 ) = 0; + virtual YWidget * createPkgSpecial ( YWidget * parent, const std::string & subwidgetName ) = 0; // NCurses only + + // + // Layout Helpers + // + + YSpacing * createHStretch ( YWidget * parent ); + YSpacing * createVStretch ( YWidget * parent ); + YSpacing * createHSpacing ( YWidget * parent, YLayoutSize_t size = 1.0 ); + YSpacing * createVSpacing ( YWidget * parent, YLayoutSize_t size = 1.0 ); + virtual YSpacing * createSpacing ( YWidget * parent, YUIDimension dim, bool stretchable = false, YLayoutSize_t size = 0.0 ) = 0; + virtual YEmpty * createEmpty ( YWidget * parent ) = 0; + + YAlignment * createLeft ( YWidget * parent ); + YAlignment * createRight ( YWidget * parent ); + YAlignment * createTop ( YWidget * parent ); + YAlignment * createBottom ( YWidget * parent ); + YAlignment * createHCenter ( YWidget * parent ); + YAlignment * createVCenter ( YWidget * parent ); + YAlignment * createHVCenter ( YWidget * parent ); + + YAlignment * createMarginBox ( YWidget * parent, YLayoutSize_t horMargin, YLayoutSize_t vertMargin ); + YAlignment * createMarginBox ( YWidget * parent, + YLayoutSize_t leftMargin, YLayoutSize_t rightMargin, + YLayoutSize_t topMargin, YLayoutSize_t bottomMargin ); + + YAlignment * createMinWidth ( YWidget * parent, YLayoutSize_t minWidth ); + YAlignment * createMinHeight ( YWidget * parent, YLayoutSize_t minHeight ); + YAlignment * createMinSize ( YWidget * parent, YLayoutSize_t minWidth, YLayoutSize_t minHeight ); + + virtual YAlignment * createAlignment ( YWidget * parent, YAlignmentType horAlignment, YAlignmentType vertAlignment ) = 0; + + YSquash * createHSquash ( YWidget * parent ); + YSquash * createVSquash ( YWidget * parent ); + YSquash * createHVSquash ( YWidget * parent ); + virtual YSquash * createSquash ( YWidget * parent, bool horSquash, bool vertSquash ) = 0; + + // + // Visual Grouping + // + + virtual YFrame * createFrame ( YWidget * parent, const std::string & label ) = 0; + virtual YCheckBoxFrame * createCheckBoxFrame ( YWidget * parent, const std::string & label, bool checked ) = 0; + + // + // Logical Grouping + // + + virtual YRadioButtonGroup * createRadioButtonGroup ( YWidget * parent ) = 0; + virtual YReplacePoint * createReplacePoint ( YWidget * parent ) = 0; + + +protected: + + friend class YUI; + + /** + * Constructor. + * + * Use YUI::widgetFactory() to get the singleton for this class. + **/ + YWidgetFactory(); + + /** + * Destructor. + **/ + virtual ~YWidgetFactory(); + +}; // class YWidgetFactory + + +#endif // YWidgetFactory_h diff --git a/src/YWidgetID.cc b/src/YWidgetID.cc new file mode 100644 index 0000000..90e8562 --- /dev/null +++ b/src/YWidgetID.cc @@ -0,0 +1,86 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWidgetID.cc + + Author: Stefan Hundhammer + +/-*/ + + +#include +#include "YWidgetID.h" + + + +YStringWidgetID::YStringWidgetID( const std::string & val ) + : _value( val ) +{ + // NOP +} + + +YStringWidgetID::~YStringWidgetID() +{ + // NOP +} + + +bool +YStringWidgetID::isEqual( YWidgetID * otherID ) const +{ + YStringWidgetID * otherStringID = + dynamic_cast (otherID); + + if ( otherStringID ) + return ( this->valueConstRef() == otherStringID->valueConstRef() ); + else + return false; +} + + +std::string +YStringWidgetID::toString() const +{ + return _value; +} + + +std::string +YStringWidgetID::value() const +{ + return _value; +} + + +const std::string & +YStringWidgetID::valueConstRef() const +{ + return _value; +} + + +std::ostream & operator<<( std::ostream & stream, const YWidgetID * id ) +{ + if ( id ) + stream << id->toString(); + else + stream << ""; + + return stream; +} diff --git a/src/YWidgetID.h b/src/YWidgetID.h new file mode 100644 index 0000000..c5a012d --- /dev/null +++ b/src/YWidgetID.h @@ -0,0 +1,118 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWidgetID.h + + Author: Stefan Hundhammer + +/-*/ + +#ifndef YWidgetID_h +#define YWidgetID_h + +#include +#include + + + +/** + * Abstract base class for widget IDs. + **/ +class YWidgetID +{ +protected: + /** + * Constructor. Protected since this is an abstract base class. + **/ + YWidgetID() {} + +public: + /** + * Destructor. + **/ + virtual ~YWidgetID() {} + + /** + * Check if this ID is equal to another. + **/ + virtual bool isEqual( YWidgetID * otherID ) const = 0; + + /** + * Convert the ID value to string. + * Used for logging and debugging. + **/ + virtual std::string toString() const = 0; + +private: + /** + * Copy constructor is disabled. + **/ + YWidgetID( const YWidgetID & orig ); +}; + + +/** + * Simple widget ID class based on strings. + **/ +class YStringWidgetID: public YWidgetID +{ +public: + + /** + * Constructor. + **/ + YStringWidgetID( const std::string & value ); + + /** + * Destructor. + **/ + virtual ~YStringWidgetID(); + + /** + * Check if this ID is equal to another. + * + * Reimplemented from YWidgetID. + **/ + virtual bool isEqual( YWidgetID * otherID ) const; + + /** + * Convert the ID value to string. + * Used for logging and debugging. + * + * Reimplemented from YWidgetID. + **/ + virtual std::string toString() const; + + /** + * Return the ID value. + **/ + std::string value() const; + + /** + * Return the ID value as a const ref. + **/ + const std::string & valueConstRef() const; + +private: + std::string _value; +}; + +std::ostream & operator<<( std::ostream & stream, const YWidgetID * id ); + + +#endif // YWidgetID_h diff --git a/src/YWidget_OptimizeChanges.h b/src/YWidget_OptimizeChanges.h new file mode 100644 index 0000000..16a3ee0 --- /dev/null +++ b/src/YWidget_OptimizeChanges.h @@ -0,0 +1,58 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWidget_OptimizeChanges.h + + Author: Michael Andres + +/-*/ + +#ifndef YWidget_OptimizeChanges_h +#define YWidget_OptimizeChanges_h + + +// Moved out of YWidget.h because it's really utterly out of place there. + +#ifndef YWidget_h +#error Do not include this file from anywhere outside YWidget.h! +#endif + +// class YWidget +// { + +public: + /** + * Helper class that calls startMultipleChanges() in its constructor + * and cares about the necessary call to doneMultipleChanges() when it goes + * out of scope. + **/ + class OptimizeChanges + { + public: + OptimizeChanges( YWidget & w ) : yw(w) { yw.startMultipleChanges(); } + ~OptimizeChanges() { yw.doneMultipleChanges(); } + private: + OptimizeChanges( const OptimizeChanges & ); // no copy + void operator=( const OptimizeChanges & ); // no assign + YWidget & yw; + }; + +// }; // class YWidget + + +#endif // YWidget_OptimizeChanges_h diff --git a/src/YWizard.cc b/src/YWizard.cc new file mode 100644 index 0000000..5218c8c --- /dev/null +++ b/src/YWizard.cc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/*-/ + + File: YWizard.cc + + Author: Stefan Hundhammer + +/-*/ + + +#define YUILogComponent "ui" +#include "YUILog.h" + +#include "YWizard.h" +#include "YPushButton.h" + + +struct YWizardPrivate +{ + YWizardPrivate( YWizardMode wizardMode ) + : wizardMode( wizardMode ) + , nextButtonIsProtected( false ) + {} + + YWizardMode wizardMode; + bool nextButtonIsProtected; +}; + + + + +YWizard::YWizard( YWidget * parent, + const std::string & backButtonLabel, + const std::string & abortButtonLabel, + const std::string & nextButtonLabel, + YWizardMode wizardMode ) + : YWidget( parent ) + , priv( new YWizardPrivate( wizardMode ) ) +{ + YUI_CHECK_NEW( priv ); + + // On the YWidget level, a Wizard has a content area and a couple of + // buttons as children, so simply subclassing from YSimpleChildManager + // won't do; a children manager that can handle more children is needed. + setChildrenManager( new YWidgetChildrenManager( this ) ); + + setDefaultStretchable( YD_HORIZ, true ); + setDefaultStretchable( YD_VERT, true ); +} + + +YWizard::~YWizard() +{ + // NOP +} + + +YWizardMode +YWizard::wizardMode() const +{ + return priv->wizardMode; +} + +bool +YWizard::nextButtonIsProtected() const +{ + return priv->nextButtonIsProtected; +} + + +void +YWizard::protectNextButton( bool protect ) +{ + priv->nextButtonIsProtected = protect; +} + + +void +YWizard::setButtonLabel( YPushButton * button, const std::string & label ) +{ + // FIXME: Throw exception? ( YUI_CHECK_PTR() ) + + if ( button ) + button->setLabel( label ); + else + yuiError() << "NULL button" << std::endl; +} + + +void +YWizard::ping() +{ + yuiDebug() << "YWizard is active" << std::endl; +} + + +const YPropertySet & +YWizard::propertySet() +{ + static YPropertySet propSet; + + if ( propSet.isEmpty() ) + { + /* + * @property std::string CurrentItem the currently selected tree item (read only) + */ + propSet.add( YProperty( YUIProperty_CurrentItem, YStringProperty, true ) ); // read-only + propSet.add( YWidget::propertySet() ); + } + + return propSet; +} + + +YPropertyValue +YWizard::getProperty( const std::string & propertyName ) +{ + propertySet().check( propertyName ); // throws exceptions if not found + + if ( propertyName == YUIProperty_CurrentItem ) return YPropertyValue( YOtherProperty ); + else + { + return YWidget::getProperty( propertyName ); + } +} diff --git a/src/YWizard.h b/src/YWizard.h new file mode 100644 index 0000000..7671cbf --- /dev/null +++ b/src/YWizard.h @@ -0,0 +1,354 @@ +/* + Copyright (C) 2000-2012 Novell, Inc + This library is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) version 3.0 of the License. This library + is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. You should have received a copy of the GNU + Lesser General Public License along with this library; if not, write + to the Free Software Foundation, Inc., 51 Franklin Street, Fifth + Floor, Boston, MA 02110-1301 USA +*/ + + +/** + + @file YWizard.h + + Author: Stefan Hundhammer + +**/ + +#ifndef YWizard_h +#define YWizard_h + +#include "YWidget.h" + +class YMacroRecorder; +class YWizardPrivate; +class YPushButton; +class YReplacePoint; + +#define YWizardID "wizard" +#define YWizardContentsReplacePointID "contents" + + +/** + * Kind of the wizard layout + **/ +enum YWizardMode +{ + YWizardMode_Standard, ///< Normal wizard (help panel or nothing) + YWizardMode_Steps, ///< Steps visible in left side panel + YWizardMode_Tree, ///< Tree in left side panel + YWizardMode_TitleOnLeft ///< Title on the left side +}; + + +/** + * A wizard is a more complex frame typically used for multi-step workflows: + * + * +------------+------------------------------------------------+ + * | | | + * | | | + * | | | + * | | | + * | | | + * | | | + * | | | + * | | | + * | Side bar | Content Area | + * | | (YReplacePoint) | + * | | | + * | | | + * | | | + * | | | + * | | | + * | | | + * | | [Back] [Abort] [Next] | + * +------------+------------------------------------------------+ + * + * The side bar can contain help text, a list of steps that are performed, or + * an embedded tree (much like the YTree widget). + * + * The client application creates the wizard and replaces the widget in the + * content area for each step. + * + * The wizard buttons can theoretically be used to do anything, but good UI + * design will stick to the model above: [Back], [Abort], [Next]. + * + * If only two buttons are desired, leave the [Back] button's label emtpy. The + * remaining two buttons will be rearranged accordingly in the button area. + * + * In the last step of a multi-step workflow, the [Next] button's label is + * customarily replaced with a label that indicates that this is the last + * step. [Accept] is recommended for that button label: [Finish] (as sometimes + * used in other environments) by no means clearly indicates that this is the + * positive ending, the final "do it" button. Worse, translations of that are + * often downright miserable: To German, [Finish] gets translated as [Beenden] + * which is the same word as "Quit" (used in menus). This does not at all tell + * the user that that button really performs the requested action the + * multi-step wizard is all about. + **/ +class YWizard: public YWidget +{ +protected: + /** + * Constructor. + * + * If only two buttons are desired, leave 'backButtonLabel' empty. + **/ + YWizard( YWidget * parent, + const std::string & backButtonLabel, + const std::string & abortButtonLabel, + const std::string & nextButtonLabel, + YWizardMode wizardMode = YWizardMode_Standard ); + +public: + + /** + * Destructor. + **/ + virtual ~YWizard(); + + /** + * Returns a descriptive name of this widget class for logging, + * debugging etc. + **/ + virtual const char * widgetClass() const { return "YWizard"; } + + + // + // Wizard basics + // + + /** + * Return the wizard mode (what kind of wizard this is): + * YWizardMode_Standard, YWizardMode_Steps, YWizardMode_Tree, YWizardMode_TitleOnLeft + **/ + YWizardMode wizardMode() const; + + /** + * Return the wizard buttons or 0 if there is no such button. + * + * Derived classes are required to implement this. + **/ + virtual YPushButton * backButton() const = 0; + virtual YPushButton * abortButton() const = 0; + virtual YPushButton * nextButton() const = 0; + + /** + * Return the internal contents ReplacePoint. + * + * Derived classes are required to implement this. + **/ + virtual YReplacePoint * contentsReplacePoint() const = 0; + + /** + * Protect the wizard's "Next" button against disabling. + **/ + void protectNextButton( bool protect ); + + /** + * Check if the wizard's "Next" button is currently protected against + * disabling. + **/ + bool nextButtonIsProtected() const; + + /** + * Set the label of one of the wizard buttons (backButton(), abortButton(), + * nextButton() ) if that button is non-null. + * + * The default implementation simply calls button->setLabel( newLabel ). + **/ + virtual void setButtonLabel( YPushButton * button, const std::string & newLabel ); + + /** + * Set the help text. + **/ + virtual void setHelpText( const std::string & helpText ) = 0; + + /** + * Set the dialog icon. An empty icon name clears the current icon. + **/ + virtual void setDialogIcon( const std::string & iconName ) = 0; + + /** + * Set the dialog title shown in the window manager's title bar. + An empty string clears the current title. + **/ + virtual void setDialogTitle( const std::string & titleText ) = 0; + + /** + * Set the dialog heading. + **/ + virtual void setDialogHeading( const std::string & headingText ) = 0; + + + // + // Steps handling + // + + /** + * Add a step for the steps panel on the side bar. + * This only adds the step to the internal list of steps. + * The display is only updated upon calling updateSteps(). + **/ + virtual void addStep( const std::string & text, const std::string & id ) = 0; + + /** + * Add a step heading for the steps panel on the side bar. + * This only adds the heading to the internal list of steps. + * The display is only updated upon calling updateSteps(). + **/ + virtual void addStepHeading( const std::string & text ) = 0; + + /** + * Delete all steps and step headings from the internal lists. + * The display is only updated upon calling updateSteps(). + **/ + virtual void deleteSteps() = 0; + + /** + * Set the current step. This also triggers updateSteps() if necessary. + **/ + virtual void setCurrentStep( const std::string & id ) = 0; + + /** + * Update the steps display: Reflect the internal steps and heading lists + * in the layout. + **/ + virtual void updateSteps() = 0; + + + // + // Tree handling + // + + /** + * Add a tree item. If "parentID" is an empty string, it will be a root + * item. 'text' is the text that will be displayed in the tree, 'id' the ID + * with which this newly created item can be referenced - and that will be + * returned when the user clicks on a tree item. + **/ + virtual void addTreeItem( const std::string & parentID, + const std::string & text, + const std::string & id ) = 0; + + /** + * Select the tree item with the specified ID, if such an item exists. + **/ + virtual void selectTreeItem( const std::string & id ) = 0; + + /** + * Returns the current tree selection or an empty string if nothing is + * selected or there is no tree. + **/ + virtual std::string currentTreeSelection() = 0; + + /** + * Delete all tree items. + **/ + virtual void deleteTreeItems() = 0; + + + // + // Menu handling + // + + /** + * Add a menu to the menu bar. If the menu bar is not visible yet, it will + * be made visible. 'text' is the user-visible text for the menu bar + * (including keyboard shortcuts marked with '&'), 'id' is the menu ID for + * later addMenuEntry() etc. calls. + **/ + virtual void addMenu( const std::string & text, + const std::string & id ) = 0; + + /** + * Add a submenu to the menu with ID 'parentMenuID'. + **/ + virtual void addSubMenu( const std::string & parentMenuID, + const std::string & text, + const std::string & id ) = 0; + + /** + * Add a menu entry to the menu with ID 'parentMenuID'. 'id' is what will + * be returned by UI::UserInput() etc. when a user activates this menu entry. + **/ + virtual void addMenuEntry( const std::string & parentMenuID, + const std::string & text, + const std::string & id ) = 0; + + /** + * Add a menu separator to a menu. + **/ + virtual void addMenuSeparator( const std::string & parentMenuID ) = 0; + + /** + * Delete all menus and hide the menu bar. + **/ + virtual void deleteMenus() = 0; + + /** + * Show a "Release Notes" button above the "Help" button in the steps panel + * with the specified label that will return the specified id to + * UI::UserInput() when clicked. + **/ + virtual void showReleaseNotesButton( const std::string & label, + const std::string & id ) = 0; + + // + // Misc + // + + /** + * Hide an existing "Release Notes" button. + **/ + virtual void hideReleaseNotesButton() = 0; + + /** + * Retranslate internal buttons that are not accessible from the outside: + * - [Help] + * - [Steps] + * - [Tree] + **/ + virtual void retranslateInternalButtons() = 0; + + /** + * NOP command to check if a YWizard is running. + **/ + void ping(); + + + // + // Property handling + // + + /** + * Get a property. + * Reimplemented from YWidget. + * + * This method may throw YUIPropertyExceptions. + **/ + virtual YPropertyValue getProperty( const std::string & propertyName ); + + /** + * Return this class's property set. + * This also initializes the property upon the first call. + * + * Reimplemented from YWidget. + **/ + virtual const YPropertySet & propertySet(); + + +private: + + ImplPtr priv; +}; + + +#endif // YWizard_h