1/*
2 * Copyright 2017 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Brian Hill
7 */
8
9
10#include "RepositoriesWindow.h"
11
12#include <Alert.h>
13#include <Application.h>
14#include <Catalog.h>
15#include <FindDirectory.h>
16#include <LayoutBuilder.h>
17#include <NodeMonitor.h>
18#include <Region.h>
19#include <Screen.h>
20
21#include "AddRepoWindow.h"
22#include "constants.h"
23
24
25#undef B_TRANSLATION_CONTEXT
26#define B_TRANSLATION_CONTEXT "RepositoriesWindow"
27
28
29RepositoriesWindow::RepositoriesWindow()
30	:
31	BWindow(BRect(50, 50, 500, 400), B_TRANSLATE_SYSTEM_NAME("Repositories"),
32		B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS
33			| B_AUTO_UPDATE_SIZE_LIMITS),
34	fAddWindow(NULL),
35	fPackageNodeStatus(B_ERROR)
36{
37	fView = new RepositoriesView();
38	BLayoutBuilder::Group<>(this, B_VERTICAL).Add(fView).End();
39
40	// Size and location on screen
41	BRect frame = fSettings.GetFrame();
42	ResizeTo(frame.Width(), frame.Height());
43	BScreen screen;
44	BRect screenFrame = screen.Frame();
45	if (screenFrame.right < frame.right || screenFrame.left > frame.left
46		|| screenFrame.top > frame.top || screenFrame.bottom < frame.bottom) {
47		CenterOnScreen();
48	}
49	else
50		MoveTo(frame.left, frame.top);
51	Show();
52
53	fMessenger.SetTo(this);
54
55	// Find the pkgman settings or cache directory
56	BPath packagePath;
57	// /boot/system/settings/package-repositories
58	status_t status = find_directory(B_SYSTEM_SETTINGS_DIRECTORY,
59		&packagePath);
60	if (status == B_OK)
61		status = packagePath.Append("package-repositories");
62	else {
63		// /boot/system/cache/package-repositories
64		status = find_directory(B_SYSTEM_CACHE_DIRECTORY, &packagePath);
65		if (status == B_OK)
66			status = packagePath.Append("package-repositories");
67	}
68	if (status == B_OK) {
69		BNode packageNode(packagePath.Path());
70		if (packageNode.InitCheck()==B_OK && packageNode.IsDirectory())
71			fPackageNodeStatus = packageNode.GetNodeRef(&fPackageNodeRef);
72	}
73
74	// watch the pkgman settings or cache directory for changes
75	_StartWatching();
76}
77
78
79RepositoriesWindow::~RepositoriesWindow()
80{
81	_StopWatching();
82}
83
84
85void
86RepositoriesWindow::_StartWatching()
87{
88	if (fPackageNodeStatus == B_OK) {
89		status_t result = watch_node(&fPackageNodeRef, B_WATCH_DIRECTORY, this);
90		fWatchingPackageNode = (result == B_OK);
91	}
92}
93
94
95void
96RepositoriesWindow::_StopWatching()
97{
98	if (fPackageNodeStatus == B_OK && fWatchingPackageNode) {
99		watch_node(&fPackageNodeRef, B_STOP_WATCHING, this);
100		fWatchingPackageNode = false;
101	}
102}
103
104
105bool
106RepositoriesWindow::QuitRequested()
107{
108	if (fView->IsTaskRunning()) {
109		BAlert *alert = new BAlert("tasks",
110			B_TRANSLATE_COMMENT("Some tasks are still running. Stop these "
111				"tasks and quit?", "Application quit alert message"),
112			B_TRANSLATE_COMMENT("Stop and quit", "Button label"),
113			kCancelLabel, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
114		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
115		int32 result = alert->Go();
116		if (result != 0)
117			return false;
118	}
119	fSettings.SetFrame(Frame());
120	be_app->PostMessage(B_QUIT_REQUESTED);
121	return BWindow::QuitRequested();
122}
123
124
125void
126RepositoriesWindow::MessageReceived(BMessage* message)
127{
128	switch (message->what)
129	{
130		case ADD_REPO_WINDOW:
131		{
132			BRect frame = Frame();
133			fAddWindow = new AddRepoWindow(frame, fMessenger);
134			break;
135		}
136
137		case ADD_REPO_URL:
138		{
139			BString url;
140			status_t result = message->FindString(key_url, &url);
141			if (result == B_OK)
142				fView->AddManualRepository(url);
143			break;
144		}
145
146		case ADD_WINDOW_CLOSED:
147		{
148			fAddWindow = NULL;
149			break;
150		}
151
152		case DELETE_KEY_PRESSED:
153		{
154			BMessage message(REMOVE_REPOS);
155			fView->MessageReceived(&message);
156			break;
157		}
158
159		// captures pkgman changes while the Repositories application is running
160		case B_NODE_MONITOR:
161		{
162			// This preflet is making the changes, so ignore this message
163			if (fView->IsTaskRunning())
164				break;
165
166			int32 opcode;
167			if (message->FindInt32("opcode", &opcode) == B_OK) {
168				switch (opcode)
169				{
170					case B_ATTR_CHANGED:
171					case B_ENTRY_CREATED:
172					case B_ENTRY_REMOVED:
173					{
174						PostMessage(UPDATE_LIST, fView);
175						break;
176					}
177				}
178			}
179			break;
180		}
181
182		default:
183			BWindow::MessageReceived(message);
184	}
185}
186