Index: src/optionsDialog.h
===================================================================
--- src/optionsDialog.h (revision 2705)
+++ src/optionsDialog.h (working copy)
@@ -170,7 +170,13 @@
void editColorFore();
void editColorBack();
+ //---------------------------------------------------------------------------
+ // User commands
+ void userCommandSelected( int cmd );
+ void userCommandTextChanged(const QString &newStr);
+ void userCommandTitleTextChanged(const QString &newStr);
+
private:
/*----- member functions -----*/
Index: src/app.h
===================================================================
--- src/app.h (revision 2705)
+++ src/app.h (working copy)
@@ -285,6 +285,7 @@
void ignoreFileRight();
void helpManPage();
void helpAbout();
+ void fillUserMenu();
//
// Keyboard accelerators cursor motion callbacks.
@@ -309,7 +310,11 @@
void fontSizeIncrease();
void fontSizeDecrease();
//
-
+
+ // User-specified
+ //
+ void userInvoke(int id);
+ //
signals:
// Signal emitted when the cursor changes line.
@@ -404,6 +409,9 @@
// Get the merged filename.
QString getMergedFilename() const;
+ // Get a user command
+ QString getUserCommand(unsigned int id) const;
+
// Compute if there is even a single byte different between the files.
bool computeAbsoluteDifference() const;
@@ -453,6 +461,7 @@
QkPopupMenu* _displayMenu;
QkPopupMenu* _hordiffMenu;
QkPopupMenu* _windowsMenu;
+ QkPopupMenu* _userMenu;
int _menuids[ MAX_MENUIDS ];
QWidget* _overviewArea;
QLabel* _remUnselView;
Index: src/optionsDialog.cpp
===================================================================
--- src/optionsDialog.cpp (revision 2705)
+++ src/optionsDialog.cpp (working copy)
@@ -289,6 +289,16 @@
// Make this dialog an observer of the resources.
connect( resourcesPtr, SIGNAL( changed() ), this, SLOT( synchronize() ) );
+
+ //---------------------------------------------------------------------------
+ // User menu
+
+ connect( _comboUserCommand, SIGNAL( activated(int) ),
+ this, SLOT( userCommandSelected(int) ) );
+ connect( _editUserCommand, SIGNAL( textChanged(const QString &) ),
+ this, SLOT( userCommandTextChanged(const QString &) ) );
+ connect( _editUserCommandTitle, SIGNAL( textChanged(const QString &) ),
+ this, SLOT( userCommandTitleTextChanged(const QString &) ) );
}
//------------------------------------------------------------------------------
@@ -466,6 +476,13 @@
_labelEditBack->update();
}
}
+
+ //---------------------------------------------------------------------------
+ // User menu
+
+ int n = _comboUserCommand->currentItem( );
+ _editUserCommandTitle->setText( resources.getUserCommandTitle( n ) );
+ _editUserCommand->setText( resources.getUserCommand( n ) );
}
//------------------------------------------------------------------------------
@@ -887,6 +904,37 @@
//------------------------------------------------------------------------------
//
+void XxOptionsDialog::userCommandSelected( int cmd )
+{
+ _comboUserCommand->setCurrentItem( cmd );
+ // Redraw the widgets
+ synchronize();
+}
+
+void XxOptionsDialog::userCommandTextChanged(const QString &newStr)
+{
+ XxResources& resources = _app->getResourcesNC();
+
+ resources.setUserCommand( (unsigned int) _comboUserCommand->currentItem(), newStr );
+ // Redraw the widgets
+ synchronize();
+ // Recreate the menu
+ _app->fillUserMenu();
+}
+
+void XxOptionsDialog::userCommandTitleTextChanged(const QString &newStr)
+{
+ XxResources& resources = _app->getResourcesNC();
+
+ resources.setUserCommandTitle( (unsigned int) _comboUserCommand->currentItem(), newStr );
+ // Redraw the widgets
+ synchronize();
+ // Recreate the menu
+ _app->fillUserMenu();
+}
+
+//------------------------------------------------------------------------------
+//
bool XxOptionsDialog::isInCommand(
const QString& command,
const QString& option
Index: src/optionsDialogBase.ui
===================================================================
--- src/optionsDialogBase.ui (revision 2705)
+++ src/optionsDialogBase.ui (working copy)
@@ -1283,6 +1283,146 @@
+
+
+ UserMenu
+
+
+ User menu
+
+
+
+ layout90
+
+
+
+ 20
+ 10
+ 210
+ 50
+
+
+
+
+ unnamed
+
+
+
+ textLabel3
+
+
+ Menu item
+
+
+
+ -
+
+ Item 1
+
+
+ -
+
+ Item 2
+
+
+ -
+
+ Item 3
+
+
+
+ _comboUserCommand
+
+
+
+
+
+
+ buttonGroup4_4_3
+
+
+
+ 10
+ 60
+ 640
+ 120
+
+
+
+ User Command
+
+
+
+ TestLabel1_2_4
+
+
+
+ 10
+ 70
+ 90
+ 29
+
+
+
+ Command:
+
+
+
+
+ TestLabel1_2_4_2
+
+
+
+ 10
+ 30
+ 90
+ 29
+
+
+
+ Title:
+
+
+
+
+ _editUserCommandTitle
+
+
+
+ 100
+ 30
+ 530
+ 29
+
+
+
+
+
+
+ The title that appears for the User menu item
+
+
+
+
+ _editUserCommand
+
+
+
+ 100
+ 70
+ 530
+ 29
+
+
+
+
+
+
+ The command to execute when the menu item is selected
+
+
+
+
Index: src/app.cpp
===================================================================
--- src/app.cpp (revision 2705)
+++ src/app.cpp (working copy)
@@ -1716,6 +1716,12 @@
//---------------------------------------------------------------------------
+ // User menu
+ _userMenu = new QkPopupMenu;
+ fillUserMenu();
+
+ //---------------------------------------------------------------------------
+
// Help menu
QkPopupMenu* helpMenu = new QkPopupMenu;
helpMenu->insertItem(
@@ -1746,6 +1752,7 @@
m->insertItem( "O&ptions", _optionsMenu );
m->insertItem( "&Display", _displayMenu );
m->insertItem( "W&indows", _windowsMenu );
+ m->insertItem( "&User", _userMenu );
m->insertSeparator();
m->insertItem( "&Help", helpMenu );
}
@@ -2931,6 +2938,44 @@
//------------------------------------------------------------------------------
//
+QString XxApp::getUserCommand(unsigned int id) const
+{
+ QString name;
+
+ // FIXME: Use _cmdline?
+ name = _resources->getUserCommand(id);
+
+ QString left, middle, right;
+ XxBuffer* leftbuf = getBuffer( 0 );
+ if ( leftbuf ) {
+ left = leftbuf->getName();
+ }
+ if ( _nbFiles == 2 ) {
+ XxBuffer* rightbuf = getBuffer( 1 );
+ if ( rightbuf ) {
+ right = rightbuf->getName();
+ }
+ }
+ else {
+ XxBuffer* middlebuf = getBuffer( 1 );
+ if ( middlebuf ) {
+ middle = middlebuf->getName();
+ }
+ XxBuffer* rightbuf = getBuffer( 2 );
+ if ( rightbuf ) {
+ right = rightbuf->getName();
+ }
+ }
+
+ name.replace( QRegExp("%L"), left );
+ name.replace( QRegExp("%M"), middle );
+ name.replace( QRegExp("%R"), right );
+
+ return name;
+}
+
+//------------------------------------------------------------------------------
+//
void XxApp::saveSelectedOnly()
{
if ( _diffs.get() == 0 ) {
@@ -4138,6 +4183,23 @@
//------------------------------------------------------------------------------
//
+void XxApp::fillUserMenu()
+{
+ // Recreate the user menu
+ _userMenu->clear();
+ for ( int ii = 0; ii < USER_COMMAND_LAST; ii++ ) {
+ if ( !_resources->getUserCommand(ii).isEmpty() ) {
+ int id = _userMenu->insertItem(
+ _resources->getUserCommandTitle(ii), this, SLOT(userInvoke(int)),
+ _resources->getAccelerator( ACCEL_USER_ADD_NEW )
+ );
+ _userMenu->setItemParameter(id, ii);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+//
void XxApp::synchronizeUI()
{
if ( _filesAreDirectories == false ) {
@@ -4528,4 +4590,32 @@
}
+//------------------------------------------------------------------------------
+//
+void XxApp::userInvoke(int id)
+{
+ const char **args;
+ QStringList filenames;
+ QString command = getUserCommand(id);
+
+ XxUtil::splitArgs( command, filenames, args );
+ try {
+ XxUtil::spawnCommand( args );
+ }
+ catch ( const XxIoError& ioerr) {
+ QString text;
+ {
+ QTextOStream oss( &text );
+ oss << "There has been an error spawning user program:"
+ << ioerr.getMsg() << endl;
+ }
+ QMessageBox* box = new XxSuicideMessageBox(
+ _mainWindow, "Error.", text, QMessageBox::Warning
+ );
+ box->show();
+
+ }
+ free (args);
+}
+
XX_NAMESPACE_END
Index: src/resParser.l
===================================================================
--- src/resParser.l (revision 2705)
+++ src/resParser.l (working copy)
@@ -45,6 +45,7 @@
%s GEOM_SC
%s ACCEL_SC
+%s USER_SC USERCT_SC
%s COLOR_SC COLORBF_SC
%s COMMAND_SC
%s COMMANDSW_SC
@@ -92,6 +93,24 @@
);
}
+{id} {
+ int token = parseFromKeywordList(
+ userList, sizeof(userList)/sizeof(StringToken),
+ USERNAME, "user",
+ yytext, yylval->num
+ );
+ if ( token != ERROR_TOKEN ) {
+ BEGIN(USERCT_SC);
+ }
+ return token;
+}
+
+([cC]ommand|[tT]itle) {
+ BEGIN(INITIAL);
+ yylval->num = ( (yytext[0] == 'c') || (yytext[0] == 'C') ) ? USERCOMMAND : USERTITLE;
+ return yylval->num;
+}
+
{id} {
int token = parseFromKeywordList(
colorList, sizeof(colorList)/sizeof(StringToken),
@@ -192,6 +211,7 @@
switch ( yylval->num ) {
case PREFGEOMETRY: BEGIN(GEOM_SC); break;
case ACCEL: BEGIN(ACCEL_SC); break;
+ case USER: BEGIN(USER_SC); break;
case COLOR: BEGIN(COLOR_SC); break;
case COMMAND: BEGIN(COMMAND_SC); break;
case COMMANDSW: BEGIN(COMMANDSW_SC); break;
Index: src/resources.h
===================================================================
--- src/resources.h (revision 2705)
+++ src/resources.h (working copy)
@@ -202,6 +202,7 @@
ACCEL_IGNORE_FILE_LEFT,
ACCEL_IGNORE_FILE_MIDDLE,
ACCEL_IGNORE_FILE_RIGHT,
+ ACCEL_USER_ADD_NEW,
ACCEL_HELP_MAN_PAGE,
ACCEL_HELP_ON_CONTEXT,
ACCEL_HELP_ABOUT,
@@ -336,6 +337,13 @@
HD_MULTIPLE
};
+enum XxUserCommand {
+ USER_COMMAND1,
+ USER_COMMAND2,
+ USER_COMMAND3,
+ USER_COMMAND_LAST, // Not a real resource
+};
+
/*==============================================================================
* CLASS XxResources
*============================================================================*/
@@ -549,7 +557,15 @@
void setMergedFilename( const QString& fn );
//
+ // Get/set user command.
+ //
+ const QString& getUserCommand( unsigned int n) const;
+ void setUserCommand( unsigned n, const QString& fn );
+ const QString& getUserCommandTitle( unsigned int n) const;
+ void setUserCommandTitle( unsigned int n, const QString& fn );
+ //
+
// Return a table for the dynamic programming algorithm, if the maximum size
// of the table allows it. If not, then return 0.
int* getDynProgTable( const uint htx, const uint hty ) const;
@@ -626,6 +642,8 @@
uint _hordiffContext;
uint _showPaneMergedViewPercent;
QString _mergedFilename;
+ QString _userCommand[ USER_COMMAND_LAST ];
+ QString _userCommandTitle[ USER_COMMAND_LAST ];
// Dynamic programming table used for horizontal diffs computation.
//
Index: src/resParser.y
===================================================================
--- src/resParser.y (revision 2705)
+++ src/resParser.y (working copy)
@@ -54,6 +54,9 @@
%token ACCEL
%token ACCELNAME
+%token USER
+%token USERNAME USERCOMMAND USERTITLE
+
%token COLOR
%token COLORNAME BACK FORE
@@ -117,6 +120,7 @@
/* typed rules */
%type colorbf
+%type userct
%type boolkwd
%start xxdiffrc
@@ -134,6 +138,7 @@
| prefgeometry
| style
| accel
+ | user
| color
| boolopt
| command
@@ -211,6 +216,28 @@
}
;
+user : USER DOT USERNAME DOT userct COLON STRING
+ {
+ /*printf( "==> User %d, %d: %s\n", $3, $5, $7 );*/
+ if ($5 == USERCOMMAND)
+ RESOURCES->setUserCommand( $3, $7 );
+ else if ($5 == USERTITLE)
+ RESOURCES->setUserCommandTitle( $3, $7 );
+ else {
+ char buf[2048];
+ ::snprintf( buf, 2048,
+ "Unrecognized user command: %s\n", $7 );
+ yyerror( buf );
+ }
+
+ }
+ ;
+
+userct : USERCOMMAND
+ | USERTITLE
+ ;
+
+
color : COLOR DOT COLORNAME COLON STRING
{
/*printf( "==> color %d back: %s\n", $3, $5 );*/
Index: src/resources.inline.h
===================================================================
--- src/resources.inline.h (revision 2705)
+++ src/resources.inline.h (working copy)
@@ -240,6 +240,24 @@
//------------------------------------------------------------------------------
//
+inline const QString& XxResources::getUserCommand(unsigned int n) const
+{
+ if (n < USER_COMMAND_LAST)
+ return _userCommand[n];
+ return _userCommand[USER_COMMAND_LAST-1];
+}
+
+//------------------------------------------------------------------------------
+//
+inline const QString& XxResources::getUserCommandTitle(unsigned int n) const
+{
+ if (n < USER_COMMAND_LAST)
+ return _userCommandTitle[n];
+ return _userCommandTitle[USER_COMMAND_LAST-1];
+}
+
+//------------------------------------------------------------------------------
+//
inline void XxResources::setFbColors(
XxColor color,
const char* backstr,
Index: src/resParser.cpp
===================================================================
--- src/resParser.cpp (revision 2705)
+++ src/resParser.cpp (working copy)
@@ -91,6 +91,13 @@
"Color choice for diff hunks, and for certain other items in the text \
view." },
+ { "User", USER,
+ "User-specified commands in the User menu. The command will be executed \
+when the entry is selected in the menu. %L, %M, %R can be used as placeholders \
+for left, middle and right filenames repectively. Note that ClearCase suffixes \
+are stripped automatically. Title specifies the title in the menu for the \
+command." },
+
{ "FontApp", FONT_APP,
"General application font, used for widgets and menus." },
@@ -475,6 +482,15 @@
" Color of text region selection " }
};
+StringToken userList[] = {
+ { "UserCommand1", USER_COMMAND1,
+ "User command 1." },
+ { "UserCommand2", USER_COMMAND2,
+ "User command 2." },
+ { "UserCommand3", USER_COMMAND3,
+ "User command 3." },
+};
+
StringToken commandList[] = {
{ "DiffFiles2", CMD_DIFF_FILES_2,
"Command to use for comparing two files." },
@@ -909,6 +925,7 @@
sortTokens( STPARAM(commandSwitchList) );
sortTokens( STPARAM(showList) );
sortTokens( STPARAM(tagList) );
+ sortTokens( STPARAM(userList) );
}
//------------------------------------------------------------------------------
@@ -1177,6 +1194,20 @@
}
}
+ int nbuser = sizeof(userList)/sizeof(StringToken);
+ const char* userStr = searchTokenName( STPARAM(kwdList), USER );
+ for ( ii = 0; ii < nbuser; ++ii ) {
+ XxUserCommand bo = XxUserCommand(userList[ii]._token);
+ const QString& bc1 = res1.getUserCommand( bo );
+ const QString& bt1 = res1.getUserCommandTitle( bo );
+ if ( bc1 != res2.getUserCommand( bo ) || bt1 != res2.getUserCommandTitle( bo )) {
+ os << userStr << "." << userList[ii]._name << ".Command" << ": \""
+ << bc1 << "\"" << endl;
+ os << userStr << "." << userList[ii]._name << ".Title" << ": \""
+ << bt1 << "\"" << endl;
+ }
+ }
+
const char* initSwitchStr = searchTokenName( STPARAM(kwdList), INITSW );
for ( ii = 0; ii < nbcommandSwitch; ++ii ) {
XxCommandSwitch bo = XxCommandSwitch(commandSwitchList[ii]._token);
@@ -1353,6 +1384,19 @@
<< b1.latin1() << "\"" << endl;
}
+ int nbusercommand = sizeof(userList)/sizeof(StringToken);
+ const char* userCommandStr =
+ searchTokenName( STPARAM(kwdList), USER );
+ for ( ii = 0; ii < nbusercommand; ++ii ) {
+ XxUserCommand bo = XxUserCommand(userList[ii]._token);
+ const QString& bc1 = res.getUserCommand( bo );
+ const QString& bt1 = res.getUserCommandTitle( bo );
+ os << userCommandStr << "." << userList[ii]._name << ".Command" << ": \""
+ << bc1.latin1() << "\"" << endl;
+ os << userCommandStr << "." << userList[ii]._name << ".Title" << ": \""
+ << bt1.latin1() << "\"" << endl;
+ }
+
const char* initSwitchStr = searchTokenName( STPARAM(kwdList), INITSW );
for ( ii = 0; ii < nbcommandSwitch; ++ii ) {
XxCommandSwitch bo = XxCommandSwitch(commandSwitchList[ii]._token);
@@ -1449,7 +1493,7 @@
drbegin( os );
int nbaccel = sizeof(accelList)/sizeof(StringToken);
const StringToken* tok = searchToken( STPARAM(kwdList), ACCEL );
- os << tok->_name << "." << "[NAME]." << ": \"[ACCELERATOR]\"" << endl;
+ os << tok->_name << "." << "[NAME]" << ": \"[ACCELERATOR]\"" << endl;
drend( os );
ddbegin( os );
os << tok->_desc << endl;
@@ -1566,6 +1610,49 @@
}
{
+ drbegin( os );
+ int nbusercommands = sizeof(userList)/sizeof(StringToken);
+ const StringToken* tok = searchToken( STPARAM(kwdList), USER );
+ os << tok->_name << "." << "[NAME].[Command]"
+ << ": \"[COMMAND]\"" << endl;
+ os << tok->_name << "." << "[NAME].[Title]"
+ << ": \"[MENU TITLE]\"" << endl;
+ drend( os );
+ ddbegin( os );
+ os << tok->_desc << endl;
+
+ for ( ii = 0; ii < nbusercommands; ++ii ) {
+ const StringToken* tokc = &( userList[ii] );
+
+ drbegin( os );
+
+ os << tok->_name << "." << tokc->_name << ".Title" << ": \"";
+ if ( qApp != 0 ) {
+ os << res.getUserCommandTitle( ii );
+ }
+ else {
+ os << "<menu title>";
+ }
+ os << "\"" << endl;
+
+ os << tok->_name << "." << tokc->_name << ".Command" << ": \"";
+ if ( qApp != 0 ) {
+ os << res.getUserCommand( ii );
+ }
+ else {
+ os << "<command>";
+ }
+ os << "\"" << endl;
+
+ drend( os );
+ ddbegin( os );
+ os << tokc->_desc << endl;
+ ddend( os );
+ }
+ ddend( os );
+ }
+
+ {
int nbbool = sizeof(boolkwdList)/sizeof(StringToken);
for ( ii = 0; ii < nbbool; ++ii ) {
XxBoolOpt bo = boolMap[ boolkwdList[ii]._token - BOOLKWD_BASE ];
Index: src/resources.cpp
===================================================================
--- src/resources.cpp (revision 2705)
+++ src/resources.cpp (working copy)
@@ -800,6 +800,28 @@
//------------------------------------------------------------------------------
//
+void XxResources::setUserCommand( unsigned int n, const QString& fn )
+{
+ if (n < USER_COMMAND_LAST) {
+ _userCommand[n] = fn;
+ emit changed();
+ }
+ /* Fail silently */
+}
+
+//------------------------------------------------------------------------------
+//
+void XxResources::setUserCommandTitle( unsigned int n, const QString& fn )
+{
+ if (n < USER_COMMAND_LAST) {
+ _userCommandTitle[n] = fn;
+ emit changed();
+ }
+ /* Fail silently */
+}
+
+//------------------------------------------------------------------------------
+//
bool XxResources::compareFonts( const QFont& f1, const QFont& f2 )
{
if ( f1.rawMode() || f2.rawMode() ) {