Easyhacking: How to make a feature optional
Working on the user experience often means making a feature optional. Some users may need a feature while others may find it distracting. An example is the tooltip shown on tracked changes.
While this tooltip is useful for the review, it just overlaps the text when editing, as long the information is not shown in the document margin (tdf#34355) or if you don’t use the Track Changes deck in the sidebar for some reason. So let’s try to make an easy hack out of this.
On the search for the code pointer
Modifying any feature about Track Changes sounds like a tough nut. Luckily, there are fixed strings in the tooltip, Inserted or Deleted or Formatted, that we can use in a search (learn more in Easyhacking: How to set up your environment > Codepointer). These terms appear too many times in the source code, of course, but since the text is localized we can restrict the search to strings.hrc, and looking through the five results there is only one without additional text: STR_REDLINE_FORMAT
. Taking this variable into a new search we find edtwin2.cxx where lcl_GetRedlineHelp()
composes the tooltip. And this helper function is called at SwEditWin::RequestHelp()
when the focused content matches IsAttrAtPos::Redline.
To verify, you simply comment out sText=lcl_GetRedlineHelp(...)
– and that tooltips on tracked changes are gone.
Changing the UI
We start by adding the checkbox to the user interface. Some options to tweak the visualization are there under Tools > Options > Writer > View, which is a good place for our option. Searching for “Helplines _While Moving” reveals the right .ui file: sw/uiconfig/swriter/ui/viewoptionspage.ui.
We extend the number of rows of the GtkGrid grid3
to 6 and drop a GtkCheckButton onto the free space. Now we change the ID to “changestooltip
”, in order to easily identify the object in the code, and set its label to “_Tooltips on tracked changes” (the underscore is the mnemonic) and add “viewoptionspage|changes- tooltip” at “Context for translation” in the Edit Text dialog. That’s all.
Access to the control
Searching for viewoptionspage.ui returns the file where these options are read: sw/source/ui/config/optpage.cxx. And we just have to follow how other controls are accessed.
First, we add the variable to the header file sw/source/uibase/inc/optpage.hxx
class SwContentOptPage : public SfxTabPage {... VclPtr<CheckBox> m_pShowInlineTooltips;
and assign this variable to the control in the constructor at the C++ source
SwContentOptPage::SwContentOptPage( vcl::Window* pParent,<br> const SfxItemSet& rCoreSet ) : SfxTabPage(pParent, "ViewOptionsPage", "modules/swriter/ui/viewoptionspage.ui", &rCoreSet) { ... get (m_pShowInlineTooltips,"changestooltip");
And never forget to clean-up what you assign
void SwContentOptPage::dispose() {... m_pShowInlineTooltips.clear();
Making the property public
Looking through the other methods of the SwContentOptPage class, it becomes clear that all settings are part of SwElemItem. So we first add our variable at Reset()
and FillItemSet(),
like the other options have done.
At the class SwElemItem in we introduce a new variable — bShowInlineTooltips
—and follow how bNotes
is handled including
void SwElemItem::FillViewOptions( SwViewOption& rVOpt) const { ... rVOpt.SetShowInlineTooltips( bShowInlineTooltips ); }
In the referenced class SwViewOption, we add two functions similar to SetPostIts()
bool IsShowInlineTooltips() const { return bool(m_nCoreOptions & ViewOptFlags1::ShowInlineTooltips); } void SetShowInlineTooltips( bool b ) { b ? (m_nCoreOptions |= ViewOptFlags1::ShowInlineTooltips ) : ( m_nCoreOptions &= ~ViewOptFlags1::ShowInlineTooltips); }
and extend the enum of ViewOptFlags1
by ShowInlineTooltips
.
ShowInlineTooltips = 0x10000000,
The template below sums up all enums and needs to get adjusted too, from 0x67dfcdfe to 0x77dfcdfe.
The newly introduced property SwViewOption::IsShowInlineTooltips
can now be used at the actual function in sw/source/uibase/docvw/edtwin2.cxx
case IsAttrAtPos::Redline: { const bool bShowInlineTooltips = rSh.GetViewOptions()->IsShowInlineTooltips(); if ( bShowTrackChanges ) sText = lcl_GetRedlineHelp(*aContentAtPos.aFnd.pRedl, bBalloon); }
Storing the setting
And it’s still not enough. While these modifications may work, the user setting wouldn’t be stored. Searching for IsPostIts returns sw/source/uibase/config/usrpref.cxx where we have to add read/write functionality for the new option.
Sequence<OUString> SwContentViewConfig::GetPropertyNames() { ... static const char* aPropNames[] = { ... "Display/ShowInlineTooltips" //19 void SwContentViewConfig::ImplCommit() { ... case 19: bVal = rParent.IsShowInlineTooltips(); break; void SwContentViewConfig::Load() { ... case 19: rParent.SetShowInlineTooltips(bSet); break;
Conclusion
On the one hand, it’s surprisingly complex how a simple option is implemented. And there is always room for beautification, for example, by providing a UNO command that makes customization possible (implemented and available with release 6.1). But otherwise it’s also not a big deal to copycat what the experts have implemented in the past, and the second time you will quickly make the patch that makes thousands of people happy.
So what are you waiting for? Start hacking now!
It would be great to have 2 sidebars left and right instead of a top toolbar. Much more practical because height is more needed than width.
Hopefully someone likes the idea and there will be an extra toolbar.