How to change the status of a Context.sublime-menu item on Sublime Text? - contextmenu

I've wrote a plugin with a context menu which changes by the situation, does exists some way to do that?
plugin_menu = sublime.load_settings('Context.sublime-menu')
children = plugin_menu.get('children')
children[0]["caption"] = "Message changed"
plugin_menu.set('children', children)
sublime.save_settings('Context.sublime-menu')
I've tried with load_settings which loads it correctly but it doesn't save it, basically because it is not the right way to do it and load_settings probably should be used for .sublime-settings files.

You would have to create a command for each action, but you may be able to leverage the is_visible method. Here is an example of it's usage.
class AdvancedNewFileAtCommand(sublime_plugin.WindowCommand):
def run(self, dirs):
if len(dirs) != 1:
return
path = dirs[0]
self.window.run_command("advanced_new_file", {"initial_path": path + os.sep})
def is_visible(self, dirs):
settings = sublime.load_settings("AdvancedNewFile.sublime-settings")
return settings.get("show_sidebar_menu", False) and len(dirs) == 1
I check for a setting and the number of directories specified. This particular example is used to selectively display a Side Bar context menu.

Related

Add a widget from awful.spawn.easy_async?

I'd like to add a power-status widget but only if the system supports it (I run the same config on my desktop as my laptop). Obviously I could check the hostname, but I'd rather just check if acpi is available. Currently I've got this:
mybattery = nil
awful.spawn.easy_async("acpi",
function(stdout, stderr, reason, exit_code)
if string.find(stdout, "^Battery") then
mybattery = batteryarc_widget{
show_current_level = true,
arc_thickness = 1
}
end
end
)
Then mybattery is added as a widget. This fails, presumably because updating mybattery later doesn't update the wibar. How do I add a widget after the fact? Or is there a better way to do this? I'd rather not call acpi synchronously.
Followup:
Since this widget periodically polls acpi and pops up warnings when it fails to find a battery I didn't want to create the widget at all unless it would work. So taking Emmanuel's other suggestion, this is what I ended up with. vert_sep is just a separator widget and mybattery is added to the wibar later in the config.
mybattery = wibox.container.background()
awful.spawn.easy_async("acpi",
function(stdout, stderr, reason, exit_code)
if string.find(stdout, "^Battery") then
local batteryarc_widget =
require("awesome-wm-widgets.batteryarc-widget.batteryarc")
local w = wibox.layout.fixed.horizontal()
w:add(batteryarc_widget{
show_current_level = true,
arc_thickness = 1})
w:add(vert_sep)
mybattery.widget = w
end
end
)
There is multiple ways. You can use the layout :add() or :insert() methods [1]. It is also possible to create the widget even if it wont be used. The use visible = false or forced_width = 0 to make sure it isn't shown. This has a microscopic performance penalty, but is simpler than using the imperative layout methods. A third way would be to add a placeholder container and set its .widget later. However at that point, the visible trick seems simpler.
[1] https://awesomewm.org/apidoc/widget_layouts/wibox.layout.fixed.html#insert

VTiger Extension Module create custom field for Accounts Module

I'm working on a VTiger 6.4.0 Extension Module that is used to get company data when entering a company name in the Accounts module.
The module is almost finished, i retrieve data from a API and enter them in the input fields using JQuery.
But the problem is that i have some data that is not relative to the existing fields in the account information, so i'm trying to create some new custom fields.
Only i can't seem to figure out how to create a custom field for the Accounts module from within my Extension module.
I googled around and watched some posts on stackoverflow.
I came up with the following part of code, but this doesn't seem to work.
public function addKvkfield(){
$module = new Vtiger_Module();
$module->name = 'Accounts';
$module = $module->getInstance('Accounts');
$blockInstance = new Vtiger_Block();
$blockInstance->label = 'LBL_ACCOUNT_INFORMATION';
$blockInstance = $blockInstance->getInstance($blockInstance->label,$module);
$fieldInstance = new Vtiger_Field();
$fieldInstance->name = 'KvKNummer';
$fieldInstance->table = $module->basetable;
$fieldInstance->column = 'kvknummer';
$fieldInstance->columntype = 'VARCHAR(100)';
$fieldInstance->uitype = 2;
$fieldInstance->typeofdata = 'V~M';
$blockInstance->addField($fieldInstance);
}
The addKvkfield function is being called in the vtlib_handler module.postinstall (Couldn't find any information if this is the right way of doing this within a Extenstion Module)
vtlibhandler:
function vtlib_handler($modulename, $event_type) {
global $log;
if($event_type == 'module.postinstall') {
$this->addJSLinks();
$this->createConfigTable();
$this->addSettingsMenu();
$this->addKvkfield();
$this->updateLabels();
// TODO Handle post installation actions
} else if($event_type == 'module.disabled') {
// TODO Handle actions when this module is disabled.
} else if($event_type == 'module.enabled') {
// TODO Handle actions when this module is enabled.
} else if($event_type == 'module.preuninstall') {
// TODO Handle actions when this module is about to be deleted.
} else if($event_type == 'module.preupdate') {
// TODO Handle actions before this module is updated.
} else if($event_type == 'module.postupdate') {
$this->updateLabels();
// TODO Handle actions after this module is updated.
}
}
Hopefully someone can give me a push in the right direction.
Thanks in advance :)
I managed to succeed in creating the custom fields that i needed in the Accounts Module.
Thanks to the Vtiger Mailing List! :)
What did the trick was a small alteration of the code I've written:
public function addKvkfield(){
$module = Vtiger_Module::getInstance('Accounts');
$blockInstance = Vtiger_Block::getInstance('LBL_ACCOUNT_INFORMATION', $module);
$fieldInstance = new Vtiger_Field();
$fieldInstance->label = 'KvKNummer';
$fieldInstance->name = 'kvknummer';
$fieldInstance->column = $fieldInstance->name; // Good idea to keep name and columnname the same
$fieldInstance->columntype = 'VARCHAR(100)';
$fieldInstance->uitype = 1; // No need to use 2 anymore. Setting "M" below will introduce the Red asterisk
$fieldInstance->typeofdata = 'V~O';
$blockInstance->addField($fieldInstance);
}
The above code will create a (optional)Custom Field in the Account module.
If your writing a new module and never installed this module before you can just call the function in the vtlib_handler as i did in my question.
But in my case this did not work because I've already installed the plugin before adding the code to create the customfields.
So what i needed to do is call the function above on the vtlib_handler module.postupdate (this will add the custom field on a module update)
Only problem with this is that it'll get run every time the extenstion is updated.
So i suggest creating a if statement in the function to check if the field already exists in the vtiger_field dbtable if not run the script.
Hopefully i saved someone else some time by writing this all down :P
Goodluck!
Please refer below link
Add New Field in existing Module
Copy code from My Answer and create a new PHP file with ay name. Place that in CRM's root directory and Run into browser. Your Field will be added into your Module. You have to make sure about the parameters you set in code which you copy.

Open a libreoffice mail merged textdocument directly with swriter

I need help with opening the result of my mail merge operations directly in an new writer document.
Object mailMergeService = mcf.createInstanceWithContext(mailMergePackage, context);
XPropertySet mmProperties = UnoRuntime.queryInterface(XPropertySet.class, mailMergeService);
mmProperties.setPropertyValue("DocumentURL", templatePath);
mmProperties.setPropertyValue("DataSourceName", dbName);
mmProperties.setPropertyValue("CommandType", mmCommandType);
mmProperties.setPropertyValue("Command", mmCommand);
mmProperties.setPropertyValue("OutputType", mmOutputType);
// mmProperties.setPropertyValue("OutputURL", templateDirectory);
// mmProperties.setPropertyValue("FileNamePrefix", mmFileNamePrefix);
// mmProperties.setPropertyValue("SaveAsSingleFile", mmSaveAsSingleFile);
The mmOutputType is set as MailMergeType.SHELL
The LibreOffice API documentation says
"The output is a document shell.
The successful mail marge returns a XTextDocument based component."
So I've tried something like this
XJob job = UnoRuntime.queryInterface(XJob.class, mailMergeService);
Object mergedTextObject = job.execute(new NamedValue[0]);
String url = "private:factory/swriter";
loader.loadComponentFromURL(url, "_blank", 0, new PropertyValue[0]);
XTextDocument mergedText = UnoRuntime.queryInterface(XTextDocument.class, mergedTextObject);
XTextCursor cursor = mergedText.getText().createTextCursor();
cursor.setString(mergedText.getText().getString());
I guess I have to pass the XTextDocument component to the url-argument of the loadComponentFromURL method but I didnt find the right way to do that.
When I change the OutputType to MailMergeType.FILE the result is generated in a given directory and I can open the file and see that the mail merge succeeded. But this is not what my application should do.
Does someone know how I can open the result of the mail merge directly in an new writer document without saving the result to the hard drive?
Sincerly arthur
Hey guys I've found a simple way to open the result of my mail merge process directly.
The relevant snippets are these
XJob job = UnoRuntime.queryInterface(XJob.class, mailMergeService);
Object mergedTextObject = job.execute(new NamedValue[0]);
XTextDocument mergedText = UnoRuntime.queryInterface(XTextDocument.class, mergedTextObject);
mergedText.getCurrentController().getFrame().getContainerWindow().setVisible(true);
The last line of code made the window appear with the filled mail merge result.
I also don't need this line anymore
loader.loadComponentFromURL("private:factory/swriter", "_blank", 0, new PropertyValue[0]);
The document opens as a new instance of a swriter document. If you want to save the result as a file you can do this
mergedText.getCurrentController().getFrame().getContainerWindow().setVisible(true);
XStorable storeMM = UnoRuntime.queryInterface(XStorable.class, mergedText);
XModel modelMM = UnoRuntime.queryInterface(XModel.class, mergedText);
storeMM.storeAsURL(outputDirectory + outputFilename, modelMM.getArgs());
Sincerly
Arthur
What version of LO are you using? The SHELL constant has only been around since LO 4.4, and it is not supported by Apache OpenOffice yet, so it could be that it isn't fully implemented. However this code seems to show a working test.
If it is returning an XTextDocument, then normally I would assume the component is already open. However it sounds like you are not seeing a Writer window appear. Did you start LO in headless mode? If not, then maybe the process needs a few seconds before it can display.
Object mergedTextObject = job.execute(new NamedValue[0]);
Thread.sleep(10000);
Anyway to me it looks like your code has a mistake in it. These two lines would simply insert the text onto itself:
XTextCursor cursor = mergedText.getText().createTextCursor();
cursor.setString(mergedText.getText().getString());
Probably you intended to write something like this instead:
XTextDocument mergedText = UnoRuntime.queryInterface(XTextDocument.class, mergedTextObject);
String url = "private:factory/swriter";
XComponent xComponent = loader.loadComponentFromURL(url, "_blank", 0, new PropertyValue[0]);
XTextDocument xTextDocument = (XTextDocument)UnoRuntime.queryInterface(XTextDocument.class, xComponent);
XText xText = (XText)xTextDocument.getText();
XTextRange xTextRange = xText.getEnd();
xTextRange.setString(mergedText.getText().getString());
One more thought: getString() might just return an empty string if the entire document is in a table. If that is the case then you could use the view cursor or enumerate text content.
EDIT:
To preserve formatting including tables, you can do something like this (adapted from https://blog.oio.de/2010/10/27/copy-and-paste-without-clipboard-using-openoffice-org-api/):
// Select all.
XController xMergedTextController = mergedText.getCurrentController();
XTextViewCursorSupplier supTextViewCursor =
(XTextViewCursorSupplier) UnoRuntime.queryInterface(
XTextViewCursorSupplier.class, xMergedTextController);
XTextViewCursor oVC = supTextViewCursor.getViewCursor();
oVC.gotoStart(False) // This would not work if your document began with a table.
oVC.gotoEnd(True)
// Copy and paste.
XTransferableSupplier xTransferableSupplier = UnoRuntime.queryInterface(XTransferableSupplier.class, xMergedTextController);
XTransferable transferable = xTransferableSupplier.getTransferable();
XController xController = xComponent.getCurrentController();
XTransferableSupplier xTransferableSupplier_newDoc = UnoRuntime.queryInterface(XTransferableSupplier.class, xController);
xTransferableSupplier_newDoc.insertTransferable(transferable);

DynamicUpdateCommand stops working after QlikView restart

I'm using DynamicUpdateCommand inside a macro in this way:
sub addOrder
set choosen = ActiveDocument.Fields("NUMORD").GetPossibleValues
for i = 0 to choosen.Count - 1
set result = ActiveDocument.DynamicUpdateCommand("UPDATE * SET CHOOSE = 'S' WHERE NUMORD = '" & choosen.Item(i).text & "' " )
if result = false then
MsgBox result.ErrorMessage
end if
next
end sub
Dinamic Data Update is enabled.
It works, but, when I close QlikView and reopen it, it doesn't work anymore. Even if try reloading.
I empirically realized that to make it work again I need to click the "Save" button, even without changing anything...
How can I solve this little issue? Maybe is it connected with RAM and way of saving .qvw file to the file system?
Many thanks!
Without any other solution I ended with this workaround, which saves the document programmatically on document opening:
Document Properties... > Triggers > Document Event Triggers > OnOpen > Add Action(s)... > Add > External > Run macro > set Macro name = reactivateDynamicUpdateCommand
Tools > Edit Module...: add this subroutine:
sub reactivateDynamicUpdateCommand
' I know, it's weird
'... but needed to reactivate DynamicUpdateCommand functionality after a restart
ActiveDocument.Save
end sub
It works, though a better solution would be preferred.
Starting from version 11 Dynamic Update can be done as Actions rather than through VB macro. It is preferable to use Actions when possible. However, sometimes even using Dynamic Update action I noticed freezes similar to what you described. I ended up adding one more dummy action right after Dynamic Update (e.g. assigning a value to dummy variable or adding Selection -> Back action to compensate triggering OnSelect).

Recursive method not returning to previous line position in caller

I have been trying to find a solution to this for some time. I have found questions and answers on recursion but nothing that seemed to fit this particular situation.
I have written a class which should go through the given folder and all subfolders and rename files and folders if a particular search pattern is found.
Everything works as expected the replaceAllInDir gets called, it replaces files and folders if needed. The next step then is to do the same for all subfolders within the given folder.
So a subfolder gets identified and replaceAllInDir gets called from within itself. Let's assum the particular subfolder called does not contain any subfolders. I would then expect that we return to the parent folder and continue looking for other subfolders. But instead control is not returned to the parent calling method and the program ends.
I am aware of other ways of solving the actual use case, but I cannot explain the behaviour of ruby.
class MultiFileAndFolderRename
attr_accessor :rootDir, :searchPattern, :replacePattern
def initialize(rootDir, searchPattern, replacePattern)
#rootDir = rootDir
#searchPattern = searchPattern
#replacePattern = replacePattern
end
def execute
replaceAllInDir(#rootDir)
end
def getValidDirEntries(dir)
dirList = Dir.entries(dir)
dirList.delete('.')
dirList.delete('..')
dirList
end
def replaceAllInDir(currentDir)
Dir.chdir(currentDir)
puts "Processing directory: " + Dir.pwd
dirList = getValidDirEntries(currentDir)
dirList.each { |dirEntry|
attemptRename(dirEntry)
}
dirList = getValidDirEntries(currentDir)
dirList.each { |dirEntry|
if File.directory?(dirEntry)
newDir = currentDir + '\\' + dirEntry
rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString')
rntemp.replaceAllInDir(newDir)
end
}
end
def attemptRename(dirEntry)
if dirEntry.match(#searchPattern)
newname = dirEntry.to_s.sub(#searchPattern, #replacePattern)
FileUtils.mv(dirEntry.to_s, newname)
end
end
end
You have a bug. The first line of replaceAllInDir() is Dir.chdir(). chdir() changes the directory of the current process on a global scale. It's not call-stack dependent. So later when you move into a subdirectory and change into that, the change becomes permanent even if you return from the recursion.
You need to change back to the correct directory after any call to replaceAllInDir(). For example:
...
dirList.each { |dirEntry|
if File.directory?(dirEntry)
....
rntemp.replaceAllInDir(newDir)
Dir.chdir(currentDir) # <- Restore us back to the correct directory
end
}
I have tried your code, and I have found numerous errors in it. Perhaps if you fix them, your idea is working.
You should include in a library like that a part at the end that allows to call it from the shell: MultiFileAndFolderRename.new(ARGV[0], ARGV[1], ARGV[2]).execute if __FILE__ == $0 This ensures when you call the ruby code from the shell by ruby rename.rb test old new, your class will be instantiated, and the search and replace pattern will be set accordingly.
You shouldn't set the current directory, because that ensures that the line getValidDirEntries(currentDir) will not work. If you eg. call it for the directory test, and then change your current directory to test, inside the directory, getValidDirEntries('test') will not work like expected.
You should use only forward slashes instead of the double backward ones. So your code will work on Linux and Mac OS X as well.
When you instantiate the new instance of MultiFileAndFolderRename (which is not necessary), the arguments to the initializer are the wrong ones. Instead, you should use your current instance and just call self.replaceAllInDir(newDir) instead of rntemp = MultiFileAndFolderRename.new(newDir, 'searchString', 'replaceString');rntemp.replaceAllInDir(newDir).
I think the wrong instantiation is the major reason why it works not as expected, but the others should be fixed as well.

Resources