1 #include "ide.h"
2 
3 #define KEYGROUPNAME "Ide"
4 #define KEYNAMESPACE IdeKeys
5 #define KEYFILE      <ide/ide.key>
6 #include             <CtrlLib/key_source.h>
7 
8 using namespace IdeKeys;
9 
DoEditKeys()10 void Ide::DoEditKeys()
11 {
12 	EditKeys();
13 	AKEditor();
14 }
15 
AKEditor()16 void Ide::AKEditor()
17 {
18 	CodeEditor::find_next_key = AK_FINDNEXT().key[0];
19 	CodeEditor::find_prev_key = AK_FINDPREV().key[0];
20 	CodeEditor::replace_key = AK_DOREPLACE().key[0];
21 }
22 
PackageMenu(Bar & menu)23 void Ide::PackageMenu(Bar& menu)
24 {
25 	Project(menu);
26 }
27 
FileBookmark(Bar & menu)28 void Ide::FileBookmark(Bar& menu)
29 {
30 	int i;
31 	for(i = 0; i < 10; i++) {
32 		const Bookmark& b = bookmark[i];
33 		String txt = Format("Goto bookmark &%d", i);
34 		if(!b.file.IsEmpty())
35 			txt << " (" << bookmark[i].file << ')';
36 		menu.Add(!b.file.IsEmpty(), txt, THISBACK1(BookKey, K_CTRL_0 + i))
37 			.Key(K_CTRL_0 + i);
38 	}
39 	menu.MenuBreak();
40 	for(i = 0; i < 10; i++)
41 		menu.Add("Set", THISBACK1(BookKey, K_SHIFT_CTRL_0 + i))
42 		    .Key(K_SHIFT_CTRL_0 + i);
43 }
44 
File(Bar & menu)45 void Ide::File(Bar& menu)
46 {
47 	if (!IsEditorMode())
48 	{
49 		menu.Add(AK_SETMAIN, IdeImg::MainPackage(), THISBACK(NewMainPackage))
50 			.Enable(!IdeIsDebugLock())
51 			.Help("Select global configuration (var), select / add main project package");
52 	}
53 
54 	menu.AddMenu(AK_EDITFILE, CtrlImg::open(), THISBACK(EditAnyFile))
55 		.Help("Select any file in file selector and open it in editor");
56 	menu.AddMenu(!IsNull(GetOpposite()), AK_OPPOSITE, IdeImg::opposite(), THISBACK(GoOpposite))
57 		.Help("Switch between source and header file");
58 	menu.AddMenu(AK_SAVEFILE, CtrlImg::save(), THISBACK(DoSaveFile))
59 		.Help("Save current file");
60 	if(!designer)
61 		menu.AddMenu(CanToggleReadOnly(), AK_READONLY, IdeImg::read_only(), THISBACK(ToggleReadOnly))
62 			.Check(editor.IsReadOnly())
63 			.Help("Set / clear read-only flag for current file");
64 
65 	menu.AddMenu(!designer, AK_PRINT, CtrlImg::print(), THISBACK(Print));
66 
67 //	menu.Add("Export project", THISBACK(ExportProject))
68 //		.Help("Copy all project files into given directory");
69 
70 	if(menu.IsMenuBar())
71 	{
72 		menu.Separator();
73 		menu.Add(AK_CLOSETAB, THISBACK(ClearTab))
74 		    .Help("Close the current file tab");
75 		menu.Add(AK_CLOSETABS, THISBACK(ClearTabs))
76 		    .Help("Close all file tabs");
77 		if(!designer) {
78 			menu.Add("Bookmarks", THISBACK(FileBookmark))
79 				.Help("Set one of available bookmarks (1..9, 0) on current file");
80 			menu.MenuSeparator();
81 		}
82 		menu.Add("Show/hide bottom pane", THISBACK(SwapBottom))
83 			.Check(IsBottomShown())
84 			.Key(K_ESCAPE)
85 			.Help("Show / hide bottom pane (with console, calc and browser tabs)");
86 	}
87 
88 	menu.Add(AK_PACKAGESFILES, THISBACK(SwapPackagesFiles))
89 	    .Check(weframe.IsShown());
90 
91 	menu.MenuSeparator();
92 
93 	bool split = editorsplit.GetZoom() < 0;
94 	menu.Add(AK_SPLIT, THISBACK1(KeySplit, false))
95 	    .Check(split && editorsplit.IsVert());
96 	menu.Add(AK_VSPLIT, THISBACK1(KeySplit, true))
97 	    .Check(split && editorsplit.IsHorz());
98 	menu.Add(split, AK_SWAP, THISBACK(SwapEditors));
99 
100 	menu.MenuSeparator();
101 
102 	menu.Add(AK_OPENFILEDIR, THISBACK(OpenFileFolder));
103 	menu.MenuSeparator();
104 
105 	menu.Add(AK_STATISTICS, THISBACK(Statistics))
106 		.Help("Display various statistics");
107 
108 	menu.Add("Project licences..", THISBACK(Licenses));
109 	menu.Add("Elapsed times..", THISBACK(Times));
110 
111 	menu.Add(AK_EXIT, THISBACK(Exit));
112 }
113 
OnlineSearchMenu(Bar & menu)114 void Ide::OnlineSearchMenu(Bar& menu)
115 {
116 	bool b = editor.IsSelection() || IsAlNum(editor.GetChar()) || editor.GetChar() == '_';
117 	menu.Add(b, AK_GOOGLE, IdeImg::Google(),
118 	         THISBACK(OnlineSearch));
119 	menu.Add(b, AK_GOOGLEUPP, IdeImg::GoogleUpp(), THISBACK(OnlineSearchOnTheOfficialSite));
120 }
121 
AssistEdit(Bar & menu)122 void Ide::AssistEdit(Bar& menu)
123 {
124 	bool b = !editor.IsReadOnly() && !designer;
125 	menu.Add(b, "Insert", THISBACK(InsertMenu));
126 	menu.Add(b, "Insert #include", THISBACK(InsertInclude));
127 }
128 
InsertAdvanced(Bar & bar)129 void Ide::InsertAdvanced(Bar& bar)
130 {
131 	bool b = !editor.IsReadOnly();
132 	AssistEdit(bar);
133 	bar.Add(b, "Advanced", THISBACK(EditSpecial));
134 }
135 
EditSpecial(Bar & menu)136 void Ide::EditSpecial(Bar& menu)
137 {
138 	bool b = !editor.IsReadOnly();
139 	menu.Add(AK_WORDWRAP, THISBACK(ToggleWordwrap))
140 	    .Check(wordwrap);
141 
142 	menu.Separator();
143 
144 	menu.Add(b, AK_SPACESTOTABS, THISBACK(EditMakeTabs))
145 		.Help("Convert leading blanks on each line to tabs");
146 	menu.Add(b, AK_TABSTOSPACES, THISBACK(EditMakeSpaces))
147 		.Help("Convert all tabs to spaces");
148 	menu.Add(b, AK_LINEENDINGS, THISBACK(EditMakeLineEnds))
149 		.Help("Remove tabs and spaces at line endings");
150 	menu.Add(b, AK_TRANSLATESTRING, THISBACK(TranslateString))
151 		.Help("Mark the current selection as translated string");
152 	menu.Add(b, AK_SWAPCHARS, THISBACK(SwapChars))
153 	    .Help("Transpose characters");
154 	menu.Add(AK_COPYWORD, THISBACK(CopyWord))
155 	    .Help("Copy the current identifier to the clipboard");
156 	menu.Add(b, AK_DUPLICATELINE, THISBACK(DuplicateLine))
157 	    .Help("Duplicate the current line");
158 	menu.Add(b, AK_FORMATCODE, THISBACK(FormatCode))
159 	    .Help("Reformat code in editor");
160 	menu.Add(b && editor.IsSelection(), AK_TOUPPER, THISBACK(TextToUpper))
161 	    .Help("Convert letters in selection to uppercase");
162 	menu.Add(b && editor.IsSelection(), AK_TOLOWER, THISBACK(TextToLower))
163 	    .Help("Convert letters in selection to lowercase");
164 	menu.Add(b && editor.IsSelection(), AK_TOASCII, THISBACK(TextToAscii))
165 		.Help("Covert text to 7-bit ASCII removing all accents and special symbols");
166 	menu.Add(b && editor.IsSelection(), AK_INITCAPS, THISBACK(TextInitCaps))
167 	    .Help("Capitalize the first character of words in selection");
168 	menu.Add(b && editor.IsSelection(), AK_SWAPCASE, THISBACK(SwapCase))
169 	    .Help("Swap the case of letters in selection");
170 	menu.Add(b && editor.IsSelection(), AK_TOCSTRING, THISBACK(ToCString))
171 	    .Help("Convert selection to CString");
172 	menu.Add(b && editor.IsSelection(), AK_TOCOMMENT, THISBACK(ToComment))
173 		.Help("Comment code");
174 	menu.Add(b && editor.IsSelection(), AK_COMMENTLINES, THISBACK(CommentLines))
175 		.Help("Comment code lines");
176 	menu.Add(b && editor.IsSelection(), AK_UNCOMMENT, THISBACK(UnComment))
177 		.Help("Uncomment code");
178 	menu.Add(b, AK_REFORMAT_COMMENT, THISBACK(ReformatComment))
179 	    .Help("Reformat multiline comment into paragraph");
180 	menu.Add(b, "Remove debugging logs (DDUMP...)", [=] { RemoveDs(); });
181 }
182 
SearchMenu(Bar & menu)183 void Ide::SearchMenu(Bar& menu)
184 {
185 	if(!designer) {
186 		menu.Add(AK_FIND, THISBACK(EditFind))
187 			.Help("Search for text or text pattern");
188 		menu.Add(!editor.IsReadOnly(), AK_REPLACE, THISBACK(EditReplace))
189 			.Help("Search for text or text pattern, with replace option");
190 //		menu.Add(AK_FINDSEL, THISBACK(EditFindReplacePickText))
191 //			.Help("Show find / replace dialog & set active text as the 'find' text");
192 
193 		menu.Add(AK_FINDNEXT, THISBACK(EditFindNext))
194 			.Help("Find next occurrence");
195 		menu.Add(AK_FINDPREV, THISBACK(EditFindPrevious))
196 			.Help("Find previous occurrence");
197 
198 		menu.MenuSeparator();
199 
200 		menu.Add(AK_FINDSTRING, THISBACK1(FindString, false))
201 			.Help("Find any ordinary string constant (\"\" - delimited)");
202 		menu.Add(AK_FINDSTRINGBACK, THISBACK1(FindString, true))
203 			.Help("Find any ordinary string constant (\"\" - delimited) backwards");
204 		menu.MenuSeparator();
205 	}
206 	menu.Add(AK_FINDINFILES, THISBACK1(FindInFiles, false))
207 		.Help("Find text or text pattern in subtree of given path");
208 	menu.Add(AK_REPLACEINFILES, THISBACK1(FindInFiles, true))
209 		.Help("Find text or text pattern in subtree of given path, with replace option(s)");
210 	menu.Add(AK_FINDFILE, THISBACK(FindFileName))
211 		.Help("Locate file by filename (use *, ? when you're not sure)");
212 }
213 
Edit(Bar & menu)214 void Ide::Edit(Bar& menu)
215 {
216 	bool b = !editor.IsReadOnly();
217 	if(editfile.GetCount() && editashex.Find(editfile) < 0) {
218 		menu.Add(AK_EDITASHEX, THISBACK(EditAsHex));
219 		if(!designer)
220 			menu.MenuSeparator();
221 	}
222 	if(designer) {
223 		if(FileExists(designer->GetFileName())) {
224 			menu.Add(AK_EDITASTEXT, THISBACK(EditAsText))
225 			    .Help("Edit as text file (do not use a designer)");
226 			menu.MenuSeparator();
227 		}
228 		if(menu.IsMenuBar())
229 			designer->EditMenu(menu);
230 	}
231 	else {
232 		bool selection = editor.IsAnySelection();
233 
234 		if(editor.IsView()) {
235 			menu.Add(AK_EDITASTEXT, THISBACK(EditAsText))
236 			    .Help("Edit file");
237 			menu.MenuSeparator();
238 		}
239 		if(GetFileExt(editfile) == ".t") {
240 			if(editastext.Find(editfile) >= 0)
241 				menu.Add(AK_DESIGNER, THISBACK(EditUsingDesigner))
242 				    .Help("Edit converted strings");
243 			else
244 				menu.Add(AK_EDITASTEXT, THISBACK(EditAsText))
245 				    .Help("Edit raw strings");
246 			menu.MenuSeparator();
247 		}
248 		else
249 		if(editastext.Find(editfile) >= 0/* && IsDesignerFile(editfile)*/) {
250 			menu.Add(AK_DESIGNER, THISBACK(EditUsingDesigner))
251 			    .Help(editor.GetLength() > 256*1024*1024 ? "View file" : "Edit using the designer (not as text)");
252 			menu.MenuSeparator();
253 		}
254 		menu.Add(b, "Undo", CtrlImg::undo(), callback(&editor, &LineEdit::Undo))
255 			.Key(K_CTRL_Z)
256 			.Enable(editor.IsUndo())
257 			.Help("Undo changes to text");
258 		menu.Add(b, "Redo", CtrlImg::redo(), callback(&editor, &LineEdit::Redo))
259 			.Key(K_SHIFT|K_CTRL_Z)
260 			.Enable(editor.IsRedo())
261 			.Help("Redo undone changes");
262 
263 		menu.Separator();
264 
265 		menu.Add(b, "Cut", CtrlImg::cut(), callback(&editor, &LineEdit::Cut))
266 			.Key(K_CTRL_X)
267 			.Enable(selection)
268 			.Help("Cut selection and place it on the system clipboard");
269 		menu.Add("Copy", CtrlImg::copy(), callback(&editor, &LineEdit::Copy))
270 			.Key(K_CTRL_C)
271 			.Enable(selection)
272 			.Help("Copy current selection on the system clipboard");
273 		menu.Add(b, "Paste", CtrlImg::paste(), THISBACK(EditPaste))
274 			.Key(K_CTRL_V)
275 			.Help("Insert text from clipboard at cursor location");
276 
277 		menu.Separator();
278 
279 		menu.Add("Select all", CtrlImg::select_all(), callback(&editor, &LineEdit::SelectAll))
280 			.Key(K_CTRL_A);
281 	}
282 
283 	menu.MenuSeparator();
284 
285 	menu.Add("Find and Replace", THISBACK(SearchMenu));
286 
287 	if(!designer && menu.IsMenuBar())
288 		InsertAdvanced(menu);
289 
290 	if(editor.GetLineCount() && editor.GetUtf8Line(0) == "$uvs: PENDING CONFLICT") {
291 		menu.MenuSeparator();
292 		menu.Add("Resolve pending uvs conflict", THISBACK(ResolveUvsConflict))
293 		.Help("Merge $uvs: pending conflicts generated by UVS series of versioning software");
294 	}
295 }
296 
HasMacros()297 bool Ide::HasMacros()
298 {
299 	const Array<IdeMacro>& mlist = UscMacros();
300 	if(!mlist.IsEmpty())
301 		for(int i = 0; i < mlist.GetCount(); i++) {
302 			const IdeMacro& m = mlist[i];
303 			if(!IsNull(m.menu))
304 				return true;
305 		}
306 	return false;
307 }
308 
MacroMenu(Bar & menu)309 void Ide::MacroMenu(Bar& menu)
310 {
311 	const Array<IdeMacro>& mlist = UscMacros();
312 	if(!mlist.IsEmpty() && menu.IsMenuBar()) {
313 		VectorMap< String, Vector<int> > submenu_map;
314 		for(int i = 0; i < mlist.GetCount(); i++) {
315 			const IdeMacro& m = mlist[i];
316 			if(!IsNull(m.menu)) {
317 				if(IsNull(m.submenu))
318 					submenu_map.GetAdd(Null).Add(i);
319 				else
320 					submenu_map.GetAdd(m.menu).Add(i);
321 			}
322 		}
323 		if(!submenu_map.IsEmpty()) {
324 			Vector<int> order = GetSortOrder(submenu_map.GetKeys());
325 			for(int o = 0; o < order.GetCount(); o++) {
326 				String m = submenu_map.GetKey(order[o]);
327 				Vector<int>& mx = submenu_map[order[o]];
328 				ValueArray va;
329 				for(int i = 0; i < mx.GetCount(); i++)
330 					va.Add(mx[i]);
331 				if(!IsNull(m))
332 					menu.Add(m, THISBACK1(EditMacroMenu, va));
333 				else
334 					EditMacroMenu(menu, va);
335 			}
336 		}
337 	}
338 }
339 
EditMacroMenu(Bar & menu,ValueArray mx)340 void Ide::EditMacroMenu(Bar& menu, ValueArray mx)
341 {
342 	const Array<IdeMacro>& mlist = UscMacros();
343 	Vector<String> names;
344 	Vector<int> index;
345 	names.Reserve(mx.GetCount());
346 	for(int i = 0; i < mx.GetCount(); i++) {
347 		int ii = mx[i];
348 		if(ii >= 0 && ii < mlist.GetCount()) {
349 			const IdeMacro& m = mlist[ii];
350 			names.Add(Nvl(m.submenu, m.menu));
351 			index.Add(ii);
352 		}
353 	}
354 	IndexSort(names, index);
355 	for(int i = 0; i < index.GetCount(); i++)
356 		menu.Add(names[i], THISBACK1(EditMacro, index[i]))
357 			.Key(mlist[index[i]].hotkey);
358 }
359 
EditMacro(int i)360 void Ide::EditMacro(int i)
361 {
362 	const Array<IdeMacro>& mlist = UscMacros();
363 	if(i >= 0 && i < mlist.GetCount()) {
364 		const IdeMacro& m = mlist[i];
365 		try {
366 			Vector<EscValue> arg;
367 			EscValue api = macro_api, code = m.code;
368 			::Execute(UscGlobal(), &api, code, arg, 1000000);
369 		}
370 		catch(Exc e) {
371 			PutConsole(e);
372 		}
373 	}
374 }
375 
Setup(Bar & menu)376 void Ide::Setup(Bar& menu)
377 {
378 	menu.Add("Be verbose", THISBACK(ToggleVerboseBuild))
379 		.Check(console.verbosebuild)
380 		.Help("Log detailed description of build and debug");
381 	menu.MenuSeparator();
382 	menu.Add("Settings..", IdeImg::Settings(), THISBACK(SetupFormat))
383 		.Help("Fonts, tabs, indentation, status bar");
384 	menu.Add("Abbreviations..", THISBACK(Abbreviations))
385 		.Help("Edit abbreviation keywords and code");
386 	menu.Add("Keyboard shortcuts..", THISBACK(DoEditKeys))
387 		.Help("Edit key bindings");
388 	menu.Add("Macro Manager..", THISBACK(DoMacroManager))
389 		.Help("Manage macros collection..");
390 	menu.Add("Build methods..", THISBACK(SetupBuildMethods))
391 	    .Help("Setup build methods");
392 #ifdef PLATFORM_WIN32
393 	menu.Add("Automatic build methods setup..", callback(InstantSetup))
394 	    .Help("Setups/fixes build methods and basic assemblies..");
395 #endif
396 	menu.MenuSeparator();
397 	menu.Add("Checkout and setup U++ SVN trunk sources..", [=] {
398 		if(SetupSVNTrunk()) {
399 			IdeAgain = true;
400 			Break();
401 		}
402 	});
403 
404 #ifndef PLATFORM_COCOA
405 	const Workspace& wspc = IdeWorkspace();
406 	if(wspc[0] == "ide")
407 		for(int i = 0; i < wspc.GetCount(); i++)
408 			if(wspc[i] == "ide/Core")
409 				menu.Add("Upgrade TheIDE..", [=] { UpgradeTheIDE(); });
410 #ifdef PLATFORM_POSIX
411 	menu.Add("Install theide.desktop", [=] { InstallDesktop(); });
412 #endif
413 #endif
414 
415 	if(menu.IsMenuBar())
416 		SetupMobilePlatforms(menu);
417 }
418 
SetupMobilePlatforms(Bar & menu)419 void Ide::SetupMobilePlatforms(Bar& menu)
420 {
421 	AndroidSDK androidSDK(GetAndroidSdkPath());
422 
423 	if(androidSDK.Validate()) {
424 		menu.Separator();
425 		menu.Add("Android", THISBACK1(SetupAndroidMobilePlatform, androidSDK));
426 	}
427 
428 }
429 
SetupAndroidMobilePlatform(Bar & menu,const AndroidSDK & androidSDK)430 void Ide::SetupAndroidMobilePlatform(Bar& menu, const AndroidSDK& androidSDK)
431 {
432 	menu.Add("SDK Manager", THISBACK1(LaunchAndroidSDKManager, androidSDK));
433 	menu.Add("AVD Manager", THISBACK1(LaunchAndroidAVDManager, androidSDK));
434 	menu.Add("Device monitor", THISBACK1(LauchAndroidDeviceMonitor, androidSDK));
435 }
436 
ProjectRepo(Bar & menu)437 void Ide::ProjectRepo(Bar& menu)
438 {
439 	Vector<String> w = RepoDirs(true);
440 	for(int i = 0; i < w.GetCount(); i++)
441 		menu.Add("Synchronize " + w[i], IdeImg::svn_dir(), THISBACK1(SyncRepoDir, w[i]));
442 	menu.Add("Synchronize everything..", IdeImg::svn(), THISBACK(SyncRepo));
443 }
444 
Project(Bar & menu)445 void Ide::Project(Bar& menu)
446 {
447 	if(menu.IsToolBar() && !debugger && !IsEditorMode())
448 	{
449 		mainconfiglist.Enable(idestate == EDITING);
450 		buildmode.Enable(idestate == EDITING);
451 		menu.Add(mainconfiglist, HorzLayoutZoom(180));
452 		menu.Gap(4);
453 		menu.Add(buildmode, HorzLayoutZoom(180));
454 		menu.Separator();
455 	}
456 	if(!IsEditorMode()) {
457 		WorkspaceWork::PackageMenu(menu);
458 		menu.MenuSeparator();
459 		menu.Add(AK_ORGANIZER, IdeImg::package_organizer(), THISBACK(EditWorkspace))
460 			.Help("Package dependencies, compiler & linker options, output path override");
461 		menu.Add(AK_CUSTOM, THISBACK(CustomSteps))
462 			.Help("Building intermediate files using custom commands / applications");
463 		if(menu.IsMenuBar())
464 			menu.Add(AK_MAINCONFIG, IdeImg::main_package(), THISBACK(MainConfig))
465 				.Help("Configuring compiler, operating system, output application parameters, custom flags");
466 		menu.Separator();
467 		menu.Add(AK_SYNCT, IdeImg::Language(), THISBACK1(SyncT, 0))
468 		    .Help("Synchronize all language translation files of current workspace");
469 		menu.AddMenu(AK_TRIMPORT, IdeImg::Language(), THISBACK1(SyncT, 1))
470 		    .Help("Import runtime translation file");
471 		menu.AddMenu(AK_TREXPORT, IdeImg::Language(), THISBACK1(SyncT, 2))
472 		    .Help("Export runtime translation file");
473 		if(OldLang())
474 			menu.Add("Convert s_ -> t_", THISBACK(ConvertST));
475 	}
476 	menu.MenuSeparator();
477 	FilePropertiesMenu0(menu);
478 	if(!IsEditorMode()) {
479 		menu.MenuSeparator();
480 		if(repo_dirs) {
481 			if(menu.IsMenuBar())
482 				menu.Add("Repo", THISBACK(ProjectRepo));
483 			else
484 				menu.Add("Synchronize all repositories..", IdeImg::svn(), THISBACK(SyncRepo));
485 		}
486 	}
487 }
488 
FilePropertiesMenu0(Bar & menu)489 void Ide::FilePropertiesMenu0(Bar& menu)
490 {
491 	menu.Add(IsActiveFile(), AK_FILEPROPERTIES, THISBACK(FileProperties))
492 		.Help("File properties stored in package");
493 }
494 
FilePropertiesMenu(Bar & menu)495 void Ide::FilePropertiesMenu(Bar& menu)
496 {
497 	menu.Add(IsActiveFile() && !designer, AK_SAVEENCODING, THISBACK(ChangeCharset))
498 	    .Help("Convert actual file to different encoding");
499 	menu.AddMenu(IsActiveFile() && !editfile_isfolder && !designer, AK_DIFF, IdeImg::Diff(), THISBACK(Diff))
500 	    .Help("Show differences between the current and arbitrary files");
501 	menu.AddMenu(IsActiveFile() && !editfile_isfolder && !designer && GetTargetLogPath().GetCount(),
502 	             AK_DIFFLOG, IdeImg::DiffLog(), THISBACK(DiffLog))
503 	    .Help("Show differences between the current and arbitrary files");
504 	if(editfile_repo) {
505 		String txt = String("Show ") + (editfile_repo == SVN_DIR ? "svn" : "git") + " history of file";
506 		menu.AddMenu(IsActiveFile() && !editfile_isfolder && !designer, AK_SVNDIFF, IdeImg::SvnDiff(), THISBACK(SvnHistory))
507 		    .Text(txt + "..").Help(txt);
508 		if(editfile.GetCount()) {
509 			String mine;
510 			String theirs;
511 			String original;
512 			Vector<String> r;
513 			Vector<int> rn;
514 			if(editfile_repo == SVN_DIR) {
515 				for(FindFile ff(editfile + ".*"); ff; ff.Next()) {
516 					if(ff.IsFile()) {
517 						String p = ff.GetPath();
518 						if(p.Find(".merge-left.r") >= 0)
519 							original = p;
520 						if(p.Find(".merge-right.r") >= 0)
521 							theirs = p;
522 						if(p.Find(".working") >= 0 || p.Find(".mine") >= 0)
523 							mine = p;
524 						try {
525 							CParser q(GetFileExt(~p));
526 							q.PassChar('.');
527 							q.PassChar('r');
528 							int n = q.ReadInt();
529 							if(q.IsEof()) {
530 								r.Add(p);
531 								rn.Add(n);
532 							}
533 						}
534 						catch(CParser::Error) {}
535 					}
536 				}
537 				if(IsNull(original) && IsNull(theirs) && r.GetCount() == 2) {
538 					original = r[0];
539 					theirs = r[1];
540 					if(rn[1] > rn[0])
541 						Swap(original, theirs);
542 				}
543 			}
544 			else {
545 				bool a = false, b = false, c = false;
546 				int n = min(editor.GetLineCount(), 10000);
547 				for(int i = 0; i < n; i++) { // check that we are in git conflict
548 					const String& s = editor.GetUtf8Line(i);
549 					int ch = *s;
550 					a = a || ch == '<' && s.StartsWith("<<<<<<<");
551 					b = b || ch == '=' && s.StartsWith("=======");
552 					c = c || ch == '>' && s.StartsWith(">>>>>>>");
553 				}
554 				if(a && b && c) {
555 					original = "1";
556 					mine = "2";
557 					theirs = "3";
558 				}
559 			}
560 
561 			if(mine.GetCount() || theirs.GetCount() || original.GetCount()) {
562 				menu.Sub("SVN Conflict", [=] (Bar& bar) {
563 					if(mine.GetCount() && theirs.GetCount())
564 						bar.Add("Compare mine <-> theirs", [=] { DiffFiles("mine", mine, "theirs", theirs); });
565 					if(mine.GetCount() && original.GetCount())
566 						bar.Add("Compare mine <-> original", [=] { DiffFiles("mine", mine, "original", original); });
567 					if(theirs.GetCount() && original.GetCount())
568 						bar.Add("Compare theirs <-> original", [=] { DiffFiles("theirs", theirs, "original", original); });
569 					if(mine.GetCount())
570 						bar.Add("Compare current <-> mine", [=] { DiffFiles("current", editfile, "mine", mine); });
571 					if(theirs.GetCount())
572 						bar.Add("Compare current <-> theirs", [=] { DiffFiles("current", editfile, "theirs", theirs); });
573 					if(original.GetCount())
574 						bar.Add("Compare current <-> original", [=] { DiffFiles("current", editfile, "original", original); });
575 					bar.Separator();
576 					bar.Add("Use mine", [=] {
577 						if(PromptYesNo("Do you want to overwrite current with [* mine]?")) {
578 							SaveFile();
579 							Upp::SaveFile(editfile, LoadConflictFile(mine));
580 						}
581 					});
582 					bar.Add("Use theirs", [=] {
583 						if(PromptYesNo("Do you want to overwrite current with [* theirs]?")) {
584 							SaveFile();
585 							Upp::SaveFile(editfile, LoadConflictFile(theirs));
586 						}
587 					});
588 				});
589 			}
590 		}
591 		if(editfile.GetCount() && editfile_repo == GIT_DIR) {
592 		}
593 	}
594 }
595 
BuildFileMenu(Bar & menu)596 void Ide::BuildFileMenu(Bar& menu)
597 {
598 	bool b = idestate == EDITING && !IdeIsDebugLock();
599 	menu.Add(b, "Compile " + GetFileName(editfile), IdeImg::Source(), THISBACK(FileCompile))
600 		.Key(AK_COMPILEFILE)
601 		.Help("Compile current file");
602 	menu.Add(b, "Preprocess " + GetFileName(editfile), IdeImg::Header(), THISBACK1(Preprocess, false))
603 		.Key(AK_PREPROCESSFILE)
604 		.Help("Preprocess current file into temporary file & open in editor");
605 	if(findarg(current_builder, "GCC", "CLANG") >= 0)
606 		menu.Add(b, "Show assembler code for " + GetFileName(editfile), THISBACK1(Preprocess, true))
607 			.Key(AK_ASSEMBLERCODE)
608 			.Help("Compile the file into assembler code");
609 	if(console.verbosebuild)
610 		menu.Add(b, "Internal Preprocess " + GetFileName(editfile), IdeImg::HeaderInternal(), THISBACK(PreprocessInternal));
611 }
612 
BuildPackageMenu(Bar & menu)613 void Ide::BuildPackageMenu(Bar& menu)
614 {
615 	int pi = GetPackageIndex();
616 	bool b = !IdeIsDebugLock() && idestate == EDITING && pi >= 0 && pi < IdeWorkspace().GetCount();
617 	String name;
618 	if(b)
619 		name = '\'' + IdeWorkspace()[pi] + '\'';
620 	menu.Add(b, "Build package " + name, THISBACK(PackageBuild))
621 		.Help("Build current package");
622 	menu.Add(b, "Clean package " + name, THISBACK(PackageClean))
623 		.Help("Remove all intermediate files of the current package");
624 	menu.MenuSeparator();
625 }
626 
BuildMenu(Bar & menu)627 void Ide::BuildMenu(Bar& menu)
628 {
629 	bool b = !IdeIsDebugLock();
630 	menu.Add(AK_OUTPUTMODE, THISBACK(SetupOutputMode))
631 	    .Help("Setup how to build the target");
632 	if(idestate == BUILDING)
633 		menu.Add(b, "Stop build", IdeImg::build_stop(), THISBACK(StopBuild))
634 			.Key(AK_BUILD)
635 			.Help("Stop building");
636 	else
637 		menu.Add(b, "Build", IdeImg::build_make(), THISBACK(DoBuild))
638 			.Key(AK_BUILD)
639 			.Help("Perform minimal application rebuild");
640 	b = b && idestate == EDITING;
641 	menu.Add(b, AK_CLEAN, THISBACK(Clean))
642 		.Help("Remove all intermediate files");
643 	menu.Add(b, AK_REBUILDALL, IdeImg::build_rebuild_all(), THISBACK(RebuildAll))
644 		.Help("Remove all intermediate files & build");
645 	menu.Add(b, AK_CLEANUPPOUT, THISBACK(CleanUppOut))
646 		.Help("Remove all files and subdirectories in the output & intermediate directory (see Base setup)");
647 
648 //	menu.MenuSeparator();
649 
650 //	menu.Add(b, AK_CREATEMAKEFILE, THISBACK(CreateMakefile))
651 //		.Help("Create makefile enabling IDE-independent project building");
652 
653 	menu.MenuSeparator();
654 
655 
656 	if(menu.IsMenuBar() && !menu.IsScanKeys())
657 		BuildPackageMenu(menu);
658 
659 	BuildFileMenu(menu);
660 
661 	menu.MenuSeparator();
662 
663 	menu.Add("Stop on errors", THISBACK(ToggleStopOnErrors))
664 		.Check(stoponerrors)
665 		.Help("Stop build after package when the package has errors");
666 
667 	menu.MenuSeparator();
668 
669 	bool ff = BottomIsFindInFiles();
670 	String hh = ff ? "position" : "error line";
671 	bool ffb = ff ? FFound().GetCount() : error.GetCount();
672 	menu.Add(ffb, AK_FINDNEXTERROR, THISBACK(FindNextError))
673 		.Help("Find next " + hh + "according to console pane");
674 	menu.Add(ffb, AK_FINDPREVERROR, THISBACK(FindPrevError))
675 		.Help("Find previous " + hh + "according to console pane");
676 #if defined(PLATFORM_WIN32) || defined(PLATFORM_POSIX)
677 	menu.MenuSeparator();
678 	menu.Add(!IsNull(target), AK_OPENOUTDIR, THISBACK(OpenOutputFolder));
679 #endif
680 }
681 
DebugMenu(Bar & menu)682 void Ide::DebugMenu(Bar& menu)
683 {
684 	bool b = idestate == EDITING && !IdeIsDebugLock();
685 	if(debugger) {
686 		debugger->DebugBar(menu);
687 		menu.MenuSeparator();
688 	}
689 	else {
690 		if(console.IsRunning())
691 			menu.Add("Stop!", THISBACK(StopDebug))
692 			    .Help("Stop controlled process");
693 		if(menu.IsMenuBar())
694 			menu.Add(AK_RUNOPTIONS, THISBACK(RunArgs))
695 				.Help("Current directory, command line, stdout redirection");
696 		menu.Add(b, AK_EXECUTE, IdeImg::execute(), THISBACK(BuildAndExecute))
697 			.Help("Build and execute the application");
698 		menu.Add(b, AK_DEBUG, IdeImg::debug_run(), THISBACK1(BuildAndDebug, false))
699 			.Help("Build application & run debugger");
700 		if(menu.IsMenuBar()) {
701 			menu.Add(b, AK_DEBUGTO, THISBACK1(BuildAndDebug, true))
702 				.Help("Build application & run to cursor in debugger");
703 			menu.Add(b, AK_DEBUGEXT, THISBACK(BuildAndExtDebug))
704 				.Help("Build application & run external debugger (see Base setup, default \"msdev.exe\")");
705 			menu.Add(b, AK_DEBUGFILEEXT, THISBACK(BuildAndExtDebugFile))
706 				.Help("Build application & run external debugger, trying to start with current file");
707 		#ifdef PLATFORM_POSIX
708 			if(IsValgrind())
709 				menu.Add(b, AK_VALGRIND, THISBACK(Valgrind))
710 					.Help("Build application & run in valgring");
711 		#endif
712 
713 			menu.Separator();
714 		}
715 	}
716 	if(menu.IsMenuBar()) {
717 		menu.Add(!editfile.IsEmpty() /*&& !debuglock*/, AK_BREAKPOINT, THISBACK(DebugToggleBreak))
718 			.Help("Set / clear breakpoint on current line");
719 		menu.Add(!editfile.IsEmpty(), AK_CONDBREAKPOINT, THISBACK(ConditionalBreak))
720 			.Help("Edit conditional breakpoint");
721 		menu.Add(!editfile.IsEmpty() /*&& !debuglock*/, AK_CLEARBREAKPOINTS, THISBACK(DebugClearBreakpoints))
722 			.Help("Clear all breakpoints");
723 		menu.Separator();
724 
725 		String targetLogPath = GetTargetLogPath();
726 		menu.Add(target.GetCount() && FileExists(targetLogPath), AK_OPENLOG, THISBACK1(OpenLog, targetLogPath));
727 	}
728 }
729 
BrowseMenu(Bar & menu)730 void Ide::BrowseMenu(Bar& menu)
731 {
732 	if(!IsEditorMode()) {
733 		if(menu.IsMenuBar()) {
734 			menu.AddMenu(AK_NAVIGATOR, IdeImg::Navigator(), THISBACK(ToggleNavigator))
735 				.Check(editor.IsNavigator())
736 				.Enable(!designer);
737 			menu.Add(AK_GOTO, THISBACK(SearchCode))
738 				.Enable(!designer)
739 				.Help("Go to given line");
740 			menu.Add(AK_GOTOGLOBAL, THISBACK(NavigatorDlg));
741 			menu.Add(!designer, AK_JUMPS, THISBACK(ContextGoto));
742 			menu.Add(!designer, AK_SWAPS, THISBACK(SwapS));
743 			menu.Add(!designer, AK_ASSIST, callback(&editor, &AssistEditor::Assist));
744 			menu.Add(!designer, AK_DCOPY, callback(&editor, &AssistEditor::DCopy));
745 			menu.Add(!designer, AK_VIRTUALS, callback(&editor, &AssistEditor::Virtuals));
746 			menu.Add(!designer, AK_THISBACKS, callback(&editor, &AssistEditor::Thisbacks));
747 			menu.Add(!designer, AK_COMPLETE, callback(&editor, &AssistEditor::Complete));
748 			menu.Add(!designer, AK_ABBR, callback(&editor, &AssistEditor::Abbr));
749 			menu.Add(!designer, AK_GO_TO_LINE, THISBACK(GoToLine));
750 			AssistEdit(menu);
751 			menu.MenuSeparator();
752 		}
753 
754 		menu.Add("Go back", IdeImg::AssistGoBack(), THISBACK1(History, -1))
755 			.Key(K_ALT_LEFT)
756 			.Enable(GetHistory(-1) >= 0);
757 		menu.Add("Go forward", IdeImg::AssistGoForward(), THISBACK1(History, 1))
758 			.Key(K_ALT_RIGHT)
759 			.Enable(GetHistory(1) >= 0);
760 
761 		if(menu.IsMenuBar()) {
762 			menu.MenuSeparator();
763 			menu.Add("Check source files for changes", THISBACK(CheckCodeBase));
764 			menu.Add("Rescan all source files", THISBACK(RescanCode));
765 			if(!auto_rescan)
766 				menu.Add(AK_RESCANCURRENTFILE, THISBACK(EditFileAssistSync));
767 			menu.MenuSeparator();
768 		}
769 	}
770 	else {
771 		menu.Add(!designer, AK_GO_TO_LINE, THISBACK(GoToLine));
772 		menu.MenuSeparator();
773 	}
774 
775 	if(menu.IsMenuBar()) {
776 		menu.AddMenu(AK_CALC, IdeImg::calc(), THISBACK1(ToggleBottom, BCALC))
777 	     .Check(IsBottomShown() && btabs.GetCursor() == BCALC);
778 		menu.AddMenu(AK_QTF, IdeCommonImg::Qtf(), THISBACK(Qtf));
779 		menu.AddMenu(!designer, AK_XML, IdeCommonImg::xml(), THISBACK(Xml));
780 		menu.AddMenu(!designer, AK_JSON, IdeCommonImg::json(), THISBACK(Json));
781 		menu.AddMenu(!designer, AK_ASERRORS, IdeImg::errors(), THISBACK(AsErrors));
782 		menu.AddMenu(AK_DIRDIFF, DiffImg::DirDiff(), THISBACK(DoDirDiff));
783 		menu.AddMenu(AK_PATCH, DiffImg::PatchDiff(), THISBACK(DoPatchDiff));
784 	}
785 }
786 
HelpMenu(Bar & menu)787 void Ide::HelpMenu(Bar& menu)
788 {
789 	if(!IsEditorMode()) {
790 		menu.Add(AK_BROWSETOPICS, IdeImg::help(), THISBACK(ShowTopics));
791 		menu.Add(AK_SEARCHTOPICS, THISBACK(SearchTopics));
792 	}
793 	menu.Add(AK_BROWSETOPICS_WIN, IdeImg::help_win(), THISBACK(ShowTopicsWin));
794 	menu.MenuSeparator();
795 	menu.AddMenu("Get help / report bugs..", IdeImg::Go_forward(), callback1(LaunchWebBrowser, "http://www.ultimatepp.org/forums"));
796 	menu.AddMenu("Online documentation..", IdeImg::Go_forward(), callback1(LaunchWebBrowser, "http://www.ultimatepp.org/www$uppweb$documentation$en-us.html"));
797 	menu.AddMenu("Common information..", IdeImg::Go_forward(), callback1(LaunchWebBrowser, "http://www.ultimatepp.org/www$uppweb$community$en-us.html"));
798 	menu.Separator();
799 	OnlineSearchMenu(menu);
800 	if(menu.IsMenuBar()) {
801 		menu.Separator();
802 		menu.Add(FileExists(GetIdeLogPath()), "View application log file", THISBACK(ViewIdeLogFile));
803 		menu.Separator();
804 		menu.Add("About..", IdeImg::info(), THISBACK(About));
805 	}
806 }
807 
MainMenu(Bar & menu)808 void Ide::MainMenu(Bar& menu)
809 {
810 	menu.Add("File", THISBACK(File))
811 		.Help("Package & file functions, exports, bookmarks");
812 	menu.Add("Edit", THISBACK(Edit))
813 		.Help("Clipboard, find & replace, spaces / tabs conversion, scope highlighting");
814 	if(HasMacros())
815 		menu.Add("Macro", THISBACK(MacroMenu))
816 			.Help("Editor & IDE macros");
817 	menu.Add("Project", THISBACK(Project))
818 		.Help("Package organizer, custom steps, configuration manager");
819 	if(!IsEditorMode()) {
820 		menu.Add("Build", THISBACK(BuildMenu))
821 			.Help("Building & debugging, minor build options, showing errors");
822 		menu.Add("Debug", THISBACK(DebugMenu))
823 			.Help("Debugger commands (currently supports gdb-connection only)");
824 	}
825 	menu.Add("Assist", THISBACK(BrowseMenu))
826 		.Help("Informations, code browsing and assistance");
827 	menu.Add("Setup", THISBACK(Setup))
828 		.Help("Paths, editor settings, connection to remote host");
829 	menu.Add("Help", THISBACK(HelpMenu))
830 		.Help("Help, credits and license");
831 }
832 
MainTool(Bar & bar)833 void Ide::MainTool(Bar& bar)
834 {
835 	if(!IsEditorMode()) {
836 		BrowseMenu(bar);
837 		bar.Separator();
838 	}
839 	bar.Add("Edit as text", IdeImg::EditText(), THISBACK(EditAsText))
840 	   .Check(!designer)
841 	   .Enable(!editfile_isfolder)
842 	   .Key(!designer ? 0 : K_CTRL_T);
843 	bool b = designer && !designer.Is<FileHexView>();
844 	bool d = IsDesignerFile(editfile);
845 	bar.Add("Edit using designer", IdeImg::EditDesigner(), THISBACK(EditUsingDesigner))
846 	   .Check(b || editfile_isfolder)
847 	   .Enable(d || editfile_isfolder)
848 	   .Key(b || !d ? 0 : K_CTRL_T);
849 	bar.Add("View as hex", IdeImg::EditHex(), THISBACK(EditAsHex))
850 	   .Check(designer.Is<FileHexView>())
851 	   .Enable(!editfile_isfolder)
852 	   .Key(K_CTRL_B);
853 	if(!designer)
854 		bar.Separator();
855 	Edit(bar);
856 	if(debugger) {
857 		DebugMenu(bar);
858 		bar.Separator();
859 	}
860 	Project(bar);
861 	if(!IsEditorMode()) {
862 		BuildMenu(bar);
863 		if(!debugger) {
864 			bar.Separator();
865 			DebugMenu(bar);
866 		}
867 		bar.Separator();
868 	}
869 	HelpMenu(bar);
870 #ifdef PLATFORM_COCOA
871 	bar.GapRight();
872 	bar.Add(display, HorzLayoutZoom(170));
873 #endif
874 }
875 
ConsoleMenu(Bar & menu)876 void Ide::ConsoleMenu(Bar& menu)
877 {
878 	bool selection = console.IsAnySelection();
879 	menu.Add("Copy", CtrlImg::copy(), THISBACK(ConsoleCopy))
880 		.Key(K_CTRL_C)
881 		.Enable(selection)
882 		.Help("Copy selection on system clipboard");
883 	menu.Add("Paste", CtrlImg::paste(), THISBACK(ConsolePaste))
884 		.Key(K_CTRL_V)
885 		.Help("Append selection to system console");
886 	menu.Separator();
887 	menu.Add(AK_FIND, [=] {
888 		console.FindReplace(false, true, false);
889 	});
890 	menu.Separator();
891 	menu.Add("Clear", THISBACK(ConsoleClear))
892 		.Help("Empty system console");
893 }
894 
SetBar()895 void Ide::SetBar()
896 {
897 	SetMenuBar();
898 	SetToolBar();
899 }
900 
SetMenuBar()901 void Ide::SetMenuBar()
902 {
903 #ifdef PLATFORM_COCOA
904 	SetMainMenu(THISBACK(MainMenu));
905 	menubar.Hide();
906 #else
907 	menubar.Set(THISBACK(MainMenu));
908 #endif
909 }
910 
SetToolBar()911 void Ide::SetToolBar()
912 {
913 	toolbar.Set(THISBACK(MainTool));
914 }
915